<!DOCTYPE html>
<html>

<head>
    <title>stmmac-deep-dive.md</title>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    
<style>
/* https://github.com/microsoft/vscode/blob/master/extensions/markdown-language-features/media/markdown.css */
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

body {
	font-family: var(--vscode-markdown-font-family, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif);
	font-size: var(--vscode-markdown-font-size, 14px);
	padding: 0 26px;
	line-height: var(--vscode-markdown-line-height, 22px);
	word-wrap: break-word;
}

html,footer,header{
	font-family: var(--vscode-markdown-font-family, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif);
	font-size: var(--vscode-markdown-font-size, 14px);
}

#code-csp-warning {
	position: fixed;
	top: 0;
	right: 0;
	color: white;
	margin: 16px;
	text-align: center;
	font-size: 12px;
	font-family: sans-serif;
	background-color:#444444;
	cursor: pointer;
	padding: 6px;
	box-shadow: 1px 1px 1px rgba(0,0,0,.25);
}

#code-csp-warning:hover {
	text-decoration: none;
	background-color:#007acc;
	box-shadow: 2px 2px 2px rgba(0,0,0,.25);
}

body.scrollBeyondLastLine {
	margin-bottom: calc(100vh - 22px);
}

body.showEditorSelection .code-line {
	position: relative;
}

body.showEditorSelection .code-active-line:before,
body.showEditorSelection .code-line:hover:before {
	content: "";
	display: block;
	position: absolute;
	top: 0;
	left: -12px;
	height: 100%;
}

body.showEditorSelection li.code-active-line:before,
body.showEditorSelection li.code-line:hover:before {
	left: -30px;
}

.vscode-light.showEditorSelection .code-active-line:before {
	border-left: 3px solid rgba(0, 0, 0, 0.15);
}

.vscode-light.showEditorSelection .code-line:hover:before {
	border-left: 3px solid rgba(0, 0, 0, 0.40);
}

.vscode-light.showEditorSelection .code-line .code-line:hover:before {
	border-left: none;
}

.vscode-dark.showEditorSelection .code-active-line:before {
	border-left: 3px solid rgba(255, 255, 255, 0.4);
}

.vscode-dark.showEditorSelection .code-line:hover:before {
	border-left: 3px solid rgba(255, 255, 255, 0.60);
}

.vscode-dark.showEditorSelection .code-line .code-line:hover:before {
	border-left: none;
}

.vscode-high-contrast.showEditorSelection .code-active-line:before {
	border-left: 3px solid rgba(255, 160, 0, 0.7);
}

.vscode-high-contrast.showEditorSelection .code-line:hover:before {
	border-left: 3px solid rgba(255, 160, 0, 1);
}

.vscode-high-contrast.showEditorSelection .code-line .code-line:hover:before {
	border-left: none;
}

img {
	max-width: 100%;
	max-height: 100%;
}

a {
	text-decoration: none;
}

a:hover {
	text-decoration: underline;
}

a:focus,
input:focus,
select:focus,
textarea:focus {
	outline: 1px solid -webkit-focus-ring-color;
	outline-offset: -1px;
}

hr {
	border: 0;
	height: 2px;
	border-bottom: 2px solid;
}

h1 {
	padding-bottom: 0.3em;
	line-height: 1.2;
	border-bottom-width: 1px;
	border-bottom-style: solid;
}

h1, h2, h3 {
	font-weight: normal;
}

table {
	border-collapse: collapse;
}

table > thead > tr > th {
	text-align: left;
	border-bottom: 1px solid;
}

table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
	padding: 5px 10px;
}

table > tbody > tr + tr > td {
	border-top: 1px solid;
}

blockquote {
	margin: 0 7px 0 5px;
	padding: 0 16px 0 10px;
	border-left-width: 5px;
	border-left-style: solid;
}

code {
	font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
	font-size: 1em;
	line-height: 1.357em;
}

body.wordWrap pre {
	white-space: pre-wrap;
}

pre:not(.hljs),
pre.hljs code > div {
	padding: 16px;
	border-radius: 3px;
	overflow: auto;
}

pre code {
	color: var(--vscode-editor-foreground);
	tab-size: 4;
}

/** Theming */

.vscode-light pre {
	background-color: rgba(220, 220, 220, 0.4);
}

.vscode-dark pre {
	background-color: rgba(10, 10, 10, 0.4);
}

.vscode-high-contrast pre {
	background-color: rgb(0, 0, 0);
}

.vscode-high-contrast h1 {
	border-color: rgb(0, 0, 0);
}

.vscode-light table > thead > tr > th {
	border-color: rgba(0, 0, 0, 0.69);
}

.vscode-dark table > thead > tr > th {
	border-color: rgba(255, 255, 255, 0.69);
}

.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
	border-color: rgba(0, 0, 0, 0.18);
}

.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
	border-color: rgba(255, 255, 255, 0.18);
}

</style>

<style>
/* Tomorrow Theme */
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */

/* Tomorrow Comment */
.hljs-comment,
.hljs-quote {
	color: #8e908c;
}

/* Tomorrow Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
	color: #c82829;
}

/* Tomorrow Orange */
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
	color: #f5871f;
}

/* Tomorrow Yellow */
.hljs-attribute {
	color: #eab700;
}

/* Tomorrow Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
	color: #718c00;
}

/* Tomorrow Blue */
.hljs-title,
.hljs-section {
	color: #4271ae;
}

/* Tomorrow Purple */
.hljs-keyword,
.hljs-selector-tag {
	color: #8959a8;
}

.hljs {
	display: block;
	overflow-x: auto;
	color: #4d4d4c;
	padding: 0.5em;
}

.hljs-emphasis {
	font-style: italic;
}

.hljs-strong {
	font-weight: bold;
}
</style>

<style>
/*
 * Custom MD PDF CSS
 */
html,footer,header{
	font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif, "Meiryo";

 }
body {
	font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif, "Meiryo";
	padding: 0 12px;
}

pre {
	background-color: #f8f8f8;
	border: 1px solid #cccccc;
	border-radius: 3px;
	overflow-x: auto;
	white-space: pre-wrap;
	overflow-wrap: break-word;
}

pre:not(.hljs) {
	padding: 23px;
	line-height: 19px;
}

blockquote {
	background: rgba(127, 127, 127, 0.1);
	border-color: rgba(0, 122, 204, 0.5);
}

.emoji {
	height: 1.4em;
}

code {
	font-size: 14px;
	line-height: 19px;
}

/* for inline code */
:not(pre):not(.hljs) > code {
	color: #C9AE75; /* Change the old color so it seems less like an error */
	font-size: inherit;
}

/* Page Break : use <div class="page"/> to insert page break
-------------------------------------------------------- */
.page {
	page-break-after: always;
}

</style>
<link rel="stylesheet" href="file:///r%3A/2.Travail/1.Enseignement/Cours/_1.Outils/2.Developpement/1.SCSS/main.css" type="text/css"><link rel="stylesheet" href="file:///d%3A/rdaros/Cours/_1.Outils/2.Developpement/1.SCSS/main.css" type="text/css">
</head>

<body>
    <h1 id="linux-%E7%BD%91%E5%8D%A1%E9%A9%B1%E5%8A%A8%E9%80%9A%E8%AF%BB%E5%AE%9E%E6%88%98%E4%BB%A5-stmmac-%E4%B8%BA%E4%BE%8B%E4%BB%8E%E4%B8%BB%E5%B9%B2%E5%88%B0%E7%BB%86%E8%8A%82%E7%AB%A0%E8%8A%82%E5%8C%96%E8%AE%B2%E8%A7%A3">Linux 网卡驱动通读实战：以 stmmac 为例（从主干到细节，章节化讲解）</h1>
<blockquote>
<p>说明：本文以 Synopsys DesignWare GMAC/XGMAC 通用驱动（简称 stmmac）为例，结合你工作区中的源码，系统性讲解 Linux 以太网 MAC 驱动从架构到落地实现的全流程。文章由主干到细节、按章节推进，并穿插关键源码片段与注释，帮助你“读代码=读驱动文档”。</p>
<p>代码基于你的工作区：<code>stmmac_main.c / stmmac.h / stmmac_platform.c / dwmac4_*.c / hwif.h / stmmac_ptp.c / stmmac_mdio.c</code> 等。</p>
</blockquote>
<hr>
<h2 id="%E7%9B%AE%E5%BD%95">目录</h2>
<ul>
<li>第 0 章：网卡驱动的通用框架与源码映射</li>
<li>第 1 章：整体架构与数据路径鸟瞰（含架构与数据路径 Mermaid 图）</li>
<li>第 2 章：平台集成与设备树配置（stmmac_platform.c）</li>
<li>第 3 章：关键数据结构与 HWIF 抽象（stmmac.h, hwif.h）</li>
<li>第 4 章：驱动生命周期（probe → open → running → stop → remove）</li>
<li>第 5 章：DMA/MTL 初始化与能力探测（含初始化顺序 Mermaid 图）</li>
<li>第 6 章：描述符与队列管理（dwmac4_descs.c）</li>
<li>第 7 章：发送路径 Tx（stmmac_xmit）</li>
<li>第 8 章：接收路径 Rx 与 NAPI（stmmac_rx）</li>
<li>第 9 章：中断处理与调度（stmmac_interrupt, DMA IRQ）</li>
<li>第 10 章：硬件时间戳与 PTP（stmmac_ptp.c）</li>
<li>第 11 章：MDIO/PHY 管理（stmmac_mdio.c, stmmac_init_phy）</li>
<li>第 12 章：EEE/VLAN/RSS/TC/TSO/TBS 等进阶能力</li>
<li>第 13 章：调试与问题定位（DebugFS、MMC 计数器、常见陷阱）</li>
<li>第 14 章：从主干到细节的全路径 Walkthrough（含 TX/RX 顺序图）</li>
<li>第 15 章：MAC 核心操作详解（dwmac4_core.c 要点）</li>
<li>第 16 章：VLAN/过滤/RSS 的硬件协同</li>
<li>第 17 章：PTP/IEEE 1588 细节补充（含时间戳时序图）</li>
<li>第 18 章：MDIO/PHY/PCS 的完整路径（含 C22/C45 访问流程图）</li>
<li>第 19 章：能效与拥塞控制（EEE、流控、合并）</li>
<li>第 20 章：常见集成问题与 Checklist</li>
<li>第 21 章：TSO/TBS 描述符流水线（DWMAC4 版本）</li>
<li>第 22 章：设备树（DT）与平台集成 Cookbook</li>
<li>第 23 章：ethtool 操作小抄</li>
<li>第 24 章：性能画像与调优策略</li>
<li>第 25 章：案例集（从症状到根因）</li>
<li>第 26 章：常见问题（FAQ）</li>
<li>第 27 章：Rockchip 平台 glue 深入（含初始化流程图）</li>
<li>第 28 章：DWC QoS glue</li>
<li>第 29 章：Ring vs Chain 模式的实现差异（含布局对比图）</li>
<li>第 30 章：MMC 统计计数器详解</li>
<li>第 31 章：板级 Bring-up 作战手册</li>
<li>第 32 章：合并策略调优（RIWT 与软件 coalesce）</li>
<li>第 33 章：地址宽度、IOMMU 与 EAME（扩展地址）</li>
<li>第 34 章：确定性网络（TSN）能力概览（含 EST 时间轴）</li>
<li>第 35 章：PHY/PCS 深入与链路管理</li>
<li>第 36 章：IRQ 亲和、RPS/XPS、GRO 与多队列实践</li>
<li>第 37 章：驱动统计与 ethtool 映射</li>
<li>第 38 章：PTP 验证流程（端到端）</li>
<li>第 39 章：脚本化工具与测试清单</li>
<li>第 40 章：一页纸速查与收尾</li>
<li>附录 A–D：术语速查、寄存器速览、环形索引与内存序、DMA 内存模型</li>
<li>附：逻辑完整性自检（简版）</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-0-%E7%AB%A0%E7%BD%91%E5%8D%A1%E9%A9%B1%E5%8A%A8%E7%9A%84%E9%80%9A%E7%94%A8%E6%A1%86%E6%9E%B6%E4%B8%8E%E6%BA%90%E7%A0%81%E6%98%A0%E5%B0%84">第 0 章：网卡驱动的通用框架与源码映射</h2>
<p>先用框架视角把一个 Linux 网卡驱动拆解为通用组件，再将本仓库的 stmmac 源码一一对照，便于按图索骥。</p>
<h3 id="01-%E9%80%9A%E7%94%A8%E7%BB%84%E6%88%90%E6%A1%86%E6%9E%B6">0.1 通用组成（框架）</h3>
<ul>
<li>设备与平台集成：设备树/ACPI 解析、资源映射（寄存器/IRQ/时钟/复位）、电源与时钟管理、SerDes/PCS 上电。</li>
<li>net_device 与生命周期：probe/注册 → ndo_open/stop → remove，队列启动/停止。</li>
<li>硬件抽象与能力：按 IP 版本选择 MAC/DMA/描述符 ops；探测硬件能力后裁剪功能。</li>
<li>队列/描述符/DMA/MTL：ring/chain 组织、尾指针推进、门限与 SF/阈值模式、AXI/PBL。</li>
<li>中断与 NAPI：主中断分发、DMA channel 中断、NAPI 轮询与预算控制。</li>
<li>PHY/MDIO/PCS：MDIO C22/C45 访问、PHY attach/自协商、PCS/SerDes 模式与速率控制。</li>
<li>时间同步（PTP/PHC）：子秒增量、addend、TX/RX 硬件时间戳、PPS。</li>
<li>功能与卸载：VLAN/RSS/TSO/TBS/EEE/流控/过滤器/队列路由/TC。</li>
<li>统计与诊断：MMC 计数器、内部 xstats、ethtool -S、debugfs 导出。</li>
<li>功耗与可靠性：EEE/LPI、PM runtime、安全特性与错误恢复。</li>
</ul>
<pre class="hljs"><code><div>graph LR
	A[平台/设备树] --&gt; B[probe/资源/时钟/复位]
	B --&gt; C[net_device 生命周期]
	C --&gt; D[HW 抽象与能力探测]
	D --&gt; E[DMA/MTL/队列/描述符]
	E --&gt; F[中断/NAPI]
	F --&gt; G[数据路径 TX/RX]
	D --&gt; H[PHY/MDIO/PCS]
	D --&gt; I[PTP/PHC]
	D --&gt; J[功能与卸载]
	G --&gt; K[统计/诊断]
	B --&gt; L[功耗与可靠性]
</div></code></pre>
<h3 id="02-%E5%9C%A8%E6%9C%AC%E4%BB%93%E5%BA%93%E4%B8%AD%E7%9A%84%E8%90%BD%E7%82%B9%E6%BA%90%E7%A0%81%E6%98%A0%E5%B0%84">0.2 在本仓库中的落点（源码映射）</h3>
<ul>
<li>设备与平台集成：
<ul>
<li><code>stmmac_platform.c</code>（DT 解析、plat_stmmacenet_data 构造、资源获取）</li>
<li><code>dwmac-rk.c</code>（Rockchip glue：接口模式、时钟/延时、XPCS、上电/下电、速率回调）</li>
<li><code>dwmac-dwc-qos-eth.c</code>（DWC QoS glue：AXI/DMA 配置、资源接入）</li>
</ul>
</li>
<li>net_device 与生命周期：
<ul>
<li><code>stmmac_main.c</code>：<code>stmmac_dvr_probe</code>/<code>stmmac_dvr_remove</code>、<code>stmmac_open</code>/<code>stmmac_release</code>、<code>stmmac_xmit</code></li>
</ul>
</li>
<li>硬件抽象与能力：
<ul>
<li><code>hwif.h</code>（ops 表与分发宏）、<code>stmmac_hwif_init()</code>（在 <code>stmmac_main.c</code> 中调用）</li>
<li>能力探测：<code>dwmac4_dma.c:get_hw_feature()</code> + <code>stmmac_get_hw_features()</code></li>
</ul>
</li>
<li>队列/描述符/DMA/MTL：
<ul>
<li><code>dwmac4_descs.c</code>（描述符读写/状态）</li>
<li><code>ring_mode.c</code> / <code>chain_mode.c</code>（两种模式的 DES3 语义、jumbo/SPH）</li>
<li><code>dwmac4_dma.c</code> / <code>dwmac4_lib.c</code>（DMA 通道、尾指针、模式/阈值、AXI 配置）</li>
<li><code>dwmac4_core.c</code>（MTL 队列映射/算法/权重、MAC 基本配置）</li>
</ul>
</li>
<li>中断与 NAPI：
<ul>
<li><code>stmmac_main.c</code>：<code>stmmac_interrupt</code>、<code>stmmac_dma_interrupt</code>、<code>stmmac_napi_add</code>、<code>stmmac_rx</code></li>
</ul>
</li>
<li>PHY/MDIO/PCS：
<ul>
<li><code>stmmac_mdio.c</code>（C22/C45 访问、MDIO 注册）</li>
<li><code>stmmac_main.c: stmmac_init_phy()</code>（PHY attach）</li>
<li><code>stmmac_pcs.h</code>（PCS 相关接口定义，若启用）+ <code>dwmac-rk.c</code>（XPCS 配置）</li>
</ul>
</li>
<li>时间同步（PTP/PHC）：
<ul>
<li><code>stmmac_ptp.c</code>（PHC、addend/sub-second、TX/RX TS）</li>
</ul>
</li>
<li>功能与卸载：
<ul>
<li><code>stmmac_main.c</code>（VLAN 插入、RSS 配置、EEE 控制、TSO/TBS 开关逻辑）</li>
<li><code>dwmac4_core.c</code>（过滤器、VLAN、流控、队列路由）</li>
</ul>
</li>
<li>统计与诊断：
<ul>
<li><code>mmc_core.c</code>（MMC 计数器）</li>
<li><code>stmmac_main.c</code>（xstats、debugfs 挂载点）</li>
</ul>
</li>
<li>功耗与可靠性：
<ul>
<li><code>stmmac_main.c</code>（EEE/LPI、错误恢复路径）</li>
<li><code>dwmac4_dma.c</code>（硬错误处理、阈值调整）</li>
</ul>
</li>
</ul>
<p>提示：若你的目标是“先跑通再优化”，按本章顺序定位源码最省时间：平台 glue → 生命周期 → 能力探测 → DMA/队列 → 中断/NAPI → PHY/PCS → PTP → 特性与诊断。</p>
<blockquote>
<p>注：为方便阅读，本文在引用源码处只节选关键片段，并配以行间注释。完整实现请在你的工作区对应文件中交叉查看。</p>
</blockquote>
<hr>
<h2 id="%E7%AC%AC-1-%E7%AB%A0%E6%95%B4%E4%BD%93%E6%9E%B6%E6%9E%84%E4%B8%8E%E6%95%B0%E6%8D%AE%E8%B7%AF%E5%BE%84%E9%B8%9F%E7%9E%B0">第 1 章：整体架构与数据路径鸟瞰</h2>
<p>stmmac 是 Synopsys DWMAC/DWXGMAC 内核通用驱动，面向广泛 SoC（包括 Rockchip、Amlogic、Allwinner 等）。它采用“硬件抽象+通用框架”的分层设计：</p>
<ul>
<li>顶层通用框架：<code>stmmac_main.c</code>（生命周期、收发路径、IRQ、NAPI、队列、定时器与服务任务）、<code>stmmac.h</code>（核心数据结构）。</li>
<li>平台 glue：<code>stmmac_platform.c</code>（设备树解析、资源/时钟/AXI/MTL 参数绑定、MDIO 资源、总线/复位/时钟等）。</li>
<li>硬件抽象层（HWIF）：<code>hwif.h</code> 定义了 MAC/DMA/描述符/时间戳/... 的 ops 表，运行时根据“IP 版本/变体”选择具体实现（如 DWMAC4/410/510）。</li>
<li>MAC/DMA/描述符具体实现：<code>dwmac4_core.c</code>（MAC 核心操作）、<code>dwmac4_dma.c / dwmac4_lib.c</code>（DMA 通道与 AXI/PBL/模式/IRQ）、<code>dwmac4_descs.c</code>（描述符格式与状态机）。</li>
<li>控制外设：<code>stmmac_ptp.c</code>（PTP 时钟）、<code>stmmac_mdio.c</code>（MDIO/PHY 总线与 Clause22/45）。</li>
</ul>
<p>数据路径（简化）：</p>
<ul>
<li>TX：<code>ndo_start_xmit(stmmac_xmit)</code> → 准备描述符（首/尾、VLAN/TSO/TBS/IC）→ 填写 DMA 地址 → OWN 交给 DMA → 写回 Tail Pointer → DMA 拉取发送 → 完成后在 TX NAPI/定时器中回收（当前简化实现屏蔽了 TX NAPI 部分）。</li>
<li>RX：DMA 将数据写入预分配的 RX ring buffer → 置 OWN=CPU → 中断/NAPI 调度 → <code>stmmac_rx()</code> 轮询、拼包、剥 FCS、做 checksum 判定与时间戳 → <code>napi_gro_receive()</code> 上交协议栈 → <code>stmmac_rx_refill()</code> 回填描述符并更新 Tail。</li>
</ul>
<p>中断：</p>
<ul>
<li>核心入口 <code>stmmac_interrupt()</code>，先处理 GMAC/MTL 本地中断（LPI、PCS 链路），再分发 DMA 中断至各通道，必要时调整 DMA 阈值或重置错误通道。</li>
</ul>
<p>关键“胶水”是 <code>hwif.h</code> 的 ops 表与分发宏，如 <code>stmmac_dma_init / stmmac_start_rx / stmmac_tx_status / stmmac_set_tx_owner</code> 等，驱动主干不直接面向寄存器，而是调用对应 IP 代的实现。</p>
<p>进一步看一眼 <code>hwif.h</code> 是怎么把不同 IP 版本粘起来的：</p>
<ul>
<li>定义 ops 结构体：<code>struct stmmac_desc_ops</code>、<code>struct stmmac_dma_ops</code>、<code>struct stmmac_ops</code>、<code>struct stmmac_hwtimestamp</code> 等；</li>
<li>导出不同实现：例如 <code>extern const struct stmmac_ops dwmac4_ops;</code>、<code>dwmac410_ops</code>、<code>dwmac510_ops</code>；</li>
<li>提供分发宏：如 <code>stmmac_dma_init(priv, ioaddr, cfg, atds)</code> 实际调用 <code>priv-&gt;dma_ops-&gt;init(...)</code>。</li>
</ul>
<p>这样一来，主干代码“只关心以太网驱动要做什么”，而“怎么做（具体寄存器细节）”交给 IP 专属实现，达成强解耦与可移植性。</p>
<h3 id="%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88mermaid">架构总览（Mermaid）</h3>
<pre class="hljs"><code><div>graph TD
	subgraph L[Linux 网络栈]
		A1[Socket/协议栈]
		A2[net_device API]
		A3[ethtool / NAPI]
	end

	subgraph C[驱动核心]
		B1[stmmac_main.c&lt;br/&gt;生命周期/收发/IRQ/NAPI]
		B2[stmmac_ptp.c]
		B3[stmmac_mdio.c]
	end

	subgraph P[平台集成（Glue）]
		C1[stmmac_platform.c]
		C2[dwmac-rk.c&lt;br/&gt;Rockchip glue]
		C3[dwmac-dwc-qos-eth.c]
	end

	subgraph H[HWIF 与 IP 实现]
		D1[hwif.h&lt;br/&gt;ops 分发表]
		D2[dwmac4_core.c]
		D3[dwmac4_dma.c / dwmac4_lib.c]
		D4[dwmac4_descs.c]
		D5[ring_mode.c / chain_mode.c]
		D6[mmc_core.c]
	end

	subgraph HW[硬件]
		E1[MAC / MTL / DMA]
		E2[PCS / SerDes]
		E3[PHY]
		E4[AXI / DDR]
	end

	A2 --&gt; B1
	A3 --&gt; B1
	B1 --&gt; B2
	B1 --&gt; B3
	B1 &lt;---&gt; C1
	C1 &lt;---&gt; C2
	C1 &lt;---&gt; C3
	B1 --&gt; D1
	D1 --&gt; D2
	D1 --&gt; D3
	D1 --&gt; D4
	D4 --&gt; D5
	D2 --&gt; E1
	D3 --&gt; E1
	B2 --&gt; E1
	B3 --&gt; E3
	E1 --&gt; E2
	E2 --&gt; E3
	E1 --&gt; E4
</div></code></pre>
<h3 id="%E6%95%B0%E6%8D%AE%E8%B7%AF%E5%BE%84%E6%80%BB%E8%A7%88mermaid">数据路径总览（Mermaid）</h3>
<pre class="hljs"><code><div>flowchart LR
	subgraph TX[TX]
		T0[ndo_start_xmit]
		T1[DMA 映射 skb]
		T2[准备描述符&lt;br/&gt;VLAN/CSUM/TSO/TBS]
		T3[OWN=1; wmb]
		T4[写 TX Tail]
		T5[DMA 拉取 → MAC 发送]
		T6[回收/释放 skb]
	end
	subgraph RX[RX]
		R0[DMA 写入缓冲]
		R1[OWN→CPU]
		R2[IRQ/NAPI poll]
		R3[解析状态/组包]
		R4[TS/VLAN/GRO]
		R5[napi_gro_receive]
		R6[回填描述符 OWN=1]
		R7[写 RX Tail]
	end
	T0 --&gt; T1 --&gt; T2 --&gt; T3 --&gt; T4 --&gt; T5 --&gt; T6
	R0 --&gt; R1 --&gt; R2 --&gt; R3 --&gt; R4 --&gt; R5 --&gt; R6 --&gt; R7
</div></code></pre>
<hr>
<h2 id="%E7%AC%AC-2-%E7%AB%A0%E5%B9%B3%E5%8F%B0%E9%9B%86%E6%88%90%E4%B8%8E%E8%AE%BE%E5%A4%87%E6%A0%91%E9%85%8D%E7%BD%AEstmmacplatformc">第 2 章：平台集成与设备树配置（stmmac_platform.c）</h2>
<p>平台文件负责从设备树/平台数据读取 SoC 具体的 MAC/MTL/DMA/AXI 特性、队列数量、FIFO 大小、硬件能力开关等，并按 stmmac 需要的结构组织传入主驱动。</p>
<ul>
<li>典型流程：
<ol>
<li>解析 PHY 接口（MII/RGMII/SGMII/XAUI…）、时钟、复位、AXI 窗口、MTL 队列参数；</li>
<li>映射寄存器资源、获取 IRQ；</li>
<li>构造 <code>plat_stmmacenet_data</code>，包括 <code>dma_cfg</code>、<code>axi</code>、<code>tx/rx_queues_cfg</code>、<code>rss_en</code>、<code>tso_en</code>、<code>sph_disable</code>、<code>vlan_fail_q</code> 等；</li>
<li>驱动 probe 时作为入参传递给 <code>stmmac_dvr_probe()</code>。</li>
</ol>
</li>
</ul>
<blockquote>
<p>小贴士：平台侧“把一切准备好”，主驱动才可以“高度通用”。</p>
</blockquote>
<p>常见设备树项（不同 SoC 会命名不同，示意）：</p>
<ul>
<li>时钟/复位：<code>clocks { stmmac_clk, pclk, ptp_ref }</code>、<code>resets { stmmac_rst }</code></li>
<li>PHY 连接：<code>phy-mode = &quot;rgmii&quot;|&quot;rgmii-id&quot;|&quot;sgmii&quot;</code>，<code>phy-handle = &lt;&amp;phy0&gt;</code>；</li>
<li>MTL 队列：每队列权重、调度算法、使能 CBS（音视频类流控），RX 队列路由（广播/组播/优先级）；</li>
<li>AXI 配置：固定突发、Outstanding、AddrAlign；</li>
<li>DMA：<code>pbl</code>、<code>fb</code>、<code>fixed_burst</code>、<code>eame</code>（扩展地址）等；</li>
<li>VLAN/RSS/TSO 等功能开关；</li>
</ul>
<p>平台层将这些映射到 <code>plat_stmmacenet_data</code>，在 probe 时注入主驱动。</p>
<hr>
<h2 id="%E7%AC%AC-3-%E7%AB%A0%E5%85%B3%E9%94%AE%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E-hwif-%E6%8A%BD%E8%B1%A1stmmach-hwifh">第 3 章：关键数据结构与 HWIF 抽象（stmmac.h, hwif.h）</h2>
<ul>
<li>
<p><code>struct stmmac_priv</code> 是驱动的“宇宙中心”，贯穿设备生命周期，包含：</p>
<ul>
<li>设备与寄存器：<code>device</code>、<code>dev</code>、<code>ioaddr</code>、<code>mmcaddr</code>；</li>
<li>能力与配置：<code>dma_cap</code>（硬件能力寄存器）、<code>plat</code>（平台参数）、<code>hw</code>（MAC 寄存器抽象）；</li>
<li>队列与 ring：<code>tx_queue[] / rx_queue[]</code>、每队列 ring 指针、物理地址、tail 指针等；</li>
<li>特性状态：<code>tso</code>、<code>sph</code>、<code>rss</code>、<code>eee_enabled</code>、<code>hwts_rx/tx_en</code>；</li>
<li>NAPI/IRQ/定时器：<code>channel[]</code>、<code>workqueue</code>、<code>service_task</code>、<code>txtimer</code>；</li>
<li>PTP：<code>ptp_clock</code>、<code>systime</code>、<code>sub_second_inc</code>、<code>addend</code>；</li>
<li>统计：<code>xstats</code>、<code>mmc</code>。</li>
</ul>
</li>
<li>
<p><code>hwif.h</code> 定义了多套 ops：</p>
<ul>
<li><code>stmmac_desc_ops</code>（描述符读写、准备、TSO/TBS/VLAN/TS）、</li>
<li><code>stmmac_dma_ops</code>（DMA 重置/启动/停止/模式/尾指针/IRQ）、</li>
<li><code>stmmac_ops</code>（MAC Core：收发开关、流控、队列路由、VLAN、PCS、EEE…）、</li>
<li>以及 <code>stmmac_hwtimestamp</code>、<code>stmmac_mode_ops</code>、<code>stmmac_tc_ops</code>、<code>stmmac_mmc_ops</code>。</li>
</ul>
</li>
</ul>
<p>运行时通过 <code>stmmac_hwif_init()</code> 结合 <code>plat</code>/IP 版本选择对应实现（如 dwmac4_*）。之后主干仅用 <code>stmmac_*()</code> 这套分发函数，不直接碰寄存器。</p>
<p>再看队列与 ring：</p>
<ul>
<li><code>struct stmmac_tx_queue</code>：
<ul>
<li><code>dma_tx</code>/<code>dma_etx</code>（普通/扩展描述符内存）、<code>dma_tx_phy</code>（物理地址）、<code>cur_tx</code>/<code>dirty_tx</code> 指针、<code>tx_tail_addr</code>；</li>
<li><code>tx_skbuff[]</code> 与 <code>tx_skbuff_dma[]</code> 追踪 skb 与 DMA 映射状态；</li>
<li><code>tbs</code>（Time Based Scheduling 标志）、<code>mss</code>（TSO MSS 缓存）。</li>
</ul>
</li>
<li><code>struct stmmac_rx_queue</code>：
<ul>
<li><code>dma_rx</code>/<code>dma_erx</code>、<code>dma_rx_phy</code>、<code>cur_rx</code>/<code>dirty_rx</code>、<code>rx_tail_addr</code>；</li>
<li><code>buf_pool[]</code> 管理预分配缓冲及其 DMA 地址；</li>
<li><code>state_saved</code>/<code>state</code> 用于处理跨描述符的拼包状态（LS 未到）。</li>
</ul>
</li>
</ul>
<p>这些结构加上 per-channel 的 <code>struct stmmac_channel</code>（包含 rx/tx NAPI、锁、索引），构成驱动的核心运行时状态。</p>
<hr>
<h2 id="%E7%AC%AC-4-%E7%AB%A0%E9%A9%B1%E5%8A%A8%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9Fprobe-%E2%86%92-open-%E2%86%92-running-%E2%86%92-stop-%E2%86%92-remove">第 4 章：驱动生命周期（probe → open → running → stop → remove）</h2>
<h3 id="41-%E9%A9%B1%E5%8A%A8%E6%8E%A2%E6%B5%8Bstmmacdvrprobe">4.1 驱动探测：<code>stmmac_dvr_probe()</code></h3>
<p>入口位于 <code>stmmac_main.c</code>，负责创建 net_device、初始化 HWIF、注册 MDIO/PHY、注册网卡：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_dvr_probe（节选）</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">stmmac_dvr_probe</span><span class="hljs-params">(struct vmm_device *device,
		struct plat_stmmacenet_data *plat_dat,
		struct stmmac_resources *res)</span>
</span>{
	<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">net_device</span> *<span class="hljs-title">ndev</span> = <span class="hljs-title">NULL</span>;</span>
	<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">stmmac_priv</span> *<span class="hljs-title">priv</span>;</span>
	...
	ndev = alloc_etherdev_mqs(<span class="hljs-keyword">sizeof</span>(struct stmmac_priv),
				       MTL_MAX_TX_QUEUES, MTL_MAX_RX_QUEUES);
	...
	priv = netdev_priv(ndev);
	priv-&gt;plat = plat_dat;
	priv-&gt;ioaddr = res-&gt;addr;   <span class="hljs-comment">// MAC 基址</span>
	ndev-&gt;netdev_ops = &amp;stmmac_netdev_ops;
	...
	ret = stmmac_hw_init(priv); <span class="hljs-comment">// 选择并初始化 HWIF，探测能力</span>
	...
	stmmac_check_ether_addr(priv);
	...
	<span class="hljs-keyword">if</span> (priv-&gt;hw-&gt;pcs != STMMAC_PCS_TBI &amp;&amp;
	    priv-&gt;hw-&gt;pcs != STMMAC_PCS_RTBI)
		ret = stmmac_mdio_register(ndev);
	...
	ret = stmmac_phy_setup(priv);
	...
	ret = register_netdev(ndev);
	...
}
</div></code></pre>
<p><code>stmmac_hw_init()</code> 的核心职责：</p>
<ul>
<li>选择并初始化硬件接口实现 <code>stmmac_hwif_init()</code>；</li>
<li>读取硬件能力寄存器，覆盖/合并平台传参（是否支持 TSO、RX/TX COE、VLHash、RSS、EEE、PTP、TBS/EST/FPE 等）；</li>
<li>条件开启 Rx Watchdog（RIWT）作为接收中断合并机制之一；</li>
<li>运行必要的硬件 quirks；</li>
<li>设定一些默认的软件策略（如 <code>use_riwt</code>）。</li>
</ul>
<p>驱动在“开机-关机”各阶段与内核网络栈的契约（简述）：</p>
<ul>
<li>输入：平台提供的资源（寄存器地址、IRQ）、设备树参数；内核提供 netdev 注册/回调；</li>
<li>输出：可被 ifconfig/ip link 操作的 netdev；协议栈可以通过 ndo 回调（xmit/open/stop/...）与其交互；</li>
<li>失败模式：资源分配失败、MDIO 注册失败、PHY attach 失败、DMA 初始化失败等需按层级回滚释放；</li>
<li>成功标准：注册 netdev、能 open/close、能收发包，正确响应中断并与 PHY 建链。</li>
</ul>
<h3 id="42-%E6%89%93%E5%BC%80%E8%AE%BE%E5%A4%87ndoopen--stmmacopen">4.2 打开设备：<code>ndo_open = stmmac_open</code></h3>
<p><code>stmmac_open()</code> 按顺序完成：配置 DMA ring 大小与缓冲、分配并初始化描述符、初始化硬件并启动 DMA、请求 IRQ、开启队列与 PHY：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_open（节选）</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">stmmac_open</span><span class="hljs-params">(struct net_device *dev)</span>
</span>{
	<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">stmmac_priv</span> *<span class="hljs-title">priv</span> = <span class="hljs-title">netdev_priv</span>(<span class="hljs-title">dev</span>);</span>
	...
	ret = alloc_dma_desc_resources(priv);
	ret = init_dma_desc_rings(dev, GFP_KERNEL);
	ret = stmmac_hw_setup(dev, <span class="hljs-literal">true</span>); <span class="hljs-comment">// 初始化 MAC/DMA/MTL/EEE/PTP 等</span>
	...
	ret = request_irq(dev-&gt;irq, stmmac_interrupt, IRQF_SHARED, dev-&gt;name, dev);
	...
	stmmac_enable_all_queues(priv);
	netif_tx_start_all_queues(priv-&gt;dev);
	<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</div></code></pre>
<p>真正的“硬件点火”在 <code>stmmac_hw_setup()</code>：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_hw_setup（节选）</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">stmmac_hw_setup</span><span class="hljs-params">(struct net_device *dev, <span class="hljs-keyword">bool</span> ptp_register)</span>
</span>{
	<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">stmmac_priv</span> *<span class="hljs-title">priv</span> = <span class="hljs-title">netdev_priv</span>(<span class="hljs-title">dev</span>);</span>
	...
	ret = stmmac_init_dma_engine(priv);   <span class="hljs-comment">// 复位 DMA、配置通道、设置 ring 基址/尾指针</span>
	stmmac_set_umac_addr(priv, priv-&gt;hw, dev-&gt;dev_addr, <span class="hljs-number">0</span>);
	stmmac_core_init(priv, priv-&gt;hw, dev); <span class="hljs-comment">// 初始化 MAC 核心</span>
	stmmac_mtl_configuration(priv);        <span class="hljs-comment">// 配置 MTL（队列权重/算法/映射）</span>
	stmmac_safety_feat_configuration(priv);
	ret = stmmac_rx_ipc(priv, priv-&gt;hw);   <span class="hljs-comment">// RX 硬件校验能力</span>
	stmmac_mac_set(priv, priv-&gt;ioaddr, <span class="hljs-literal">true</span>);
	stmmac_dma_operation_mode(priv);       <span class="hljs-comment">// SF/阈值模式 + bfsize</span>
	stmmac_mmc_setup(priv);                <span class="hljs-comment">// 统计计数器</span>
	ret = stmmac_init_ptp(priv);           <span class="hljs-comment">// PTP 初始化（可选注册）</span>
	...
	stmmac_set_rings_length(priv);
	... <span class="hljs-comment">// TSO/SPH/VLAN/TBS 按能力开启</span>
	stmmac_start_all_dma(priv);            <span class="hljs-comment">// 启动所有 RX/TX DMA 通道</span>
	<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</div></code></pre>
<h3 id="43-%E5%85%B3%E9%97%AD%E4%B8%8E%E7%A7%BB%E9%99%A4ndostop--stmmacreleasestmmacdvrremove">4.3 关闭与移除：<code>ndo_stop = stmmac_release</code>、<code>stmmac_dvr_remove</code></h3>
<ul>
<li><code>stmmac_release()</code>：停队列、注销 IRQ、停 DMA、释放 ring、关 MAC；</li>
<li><code>stmmac_dvr_remove()</code>：停 DMA/关 MAC/下线 netdev/（可选）SerDes 下电/注销 MDIO/销毁资源。</li>
</ul>
<p>边界与错误处理要点：</p>
<ul>
<li>在 <code>open()</code> 过程中，任何一步失败都必须回滚（比如 <code>request_irq</code> 失败要释放已申请的 IRQ、停止 DMA、释放描述符等）；</li>
<li><code>remove()</code> 顺序上需要确保先停止收发、再从协议栈移除，再释放平台资源，避免并发访问；</li>
<li>EEE/LPI 定时器在 stop 前要清理；</li>
<li>PTP 已注册时要在 teardown 过程中注销。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-5-%E7%AB%A0dmamtl-%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%8E%E8%83%BD%E5%8A%9B%E6%8E%A2%E6%B5%8Bdwmac4dmac-dwmac4corec-dwmac4libc">第 5 章：DMA/MTL 初始化与能力探测（dwmac4_dma.c, dwmac4_core.c, dwmac4_lib.c）</h2>
<p>DMA 初始化路径从 <code>stmmac_init_dma_engine()</code> 开始，完成：</p>
<ul>
<li>复位 DMA；</li>
<li><code>stmmac_dma_init()</code> 配置 AXI/PBL/突发、门限/模式；</li>
<li>为每个通道 <code>stmmac_init_rx_chan</code> / <code>stmmac_init_tx_chan</code> 绑定 ring 基址，写入尾指针（TPDR/RPDR）；</li>
<li>可选：AXI 总线参数 <code>stmmac_axi()</code>（Outstanding Request、Burst Length 等）。</li>
</ul>
<p>探测能力：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_get_hw_features（节选）</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">stmmac_get_hw_features</span><span class="hljs-params">(struct stmmac_priv *priv)</span>
</span>{
	<span class="hljs-keyword">return</span> stmmac_get_hw_feature(priv, priv-&gt;ioaddr, &amp;priv-&gt;dma_cap) == <span class="hljs-number">0</span>;
}
</div></code></pre>
<p>具体解析在 <code>dwmac4_dma.c:get_hw_feature()</code>，硬件通过 Feature 寄存器给出：队列数、TSO、EEE、TS、VLAN Hash、EST/FPE/TBS、安全特性、FIFO 尺寸等。驱动据此调整 <code>priv-&gt;plat</code>/<code>priv-&gt;hw</code> 的行为。</p>
<p>MTL 配置：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_mtl_configuration（节选）</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stmmac_mtl_configuration</span><span class="hljs-params">(struct stmmac_priv *priv)</span>
</span>{
	<span class="hljs-keyword">if</span> (tx_queues_count &gt; <span class="hljs-number">1</span>)
		stmmac_set_tx_queue_weight(priv);
	...
	stmmac_rx_queue_dma_chan_map(priv);  <span class="hljs-comment">// MTL → DMA 通道映射</span>
	stmmac_mac_enable_rx_queues(priv);   <span class="hljs-comment">// 逐队列使能</span>
	...
	stmmac_mac_config_rss(priv);         <span class="hljs-comment">// 按需开启 RSS</span>
}
</div></code></pre>
<p>DMA 工作模式（SF vs 阈值）与 bfsize：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_dma_operation_mode（节选）</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stmmac_dma_operation_mode</span><span class="hljs-params">(struct stmmac_priv *priv)</span>
</span>{
	<span class="hljs-keyword">if</span> (priv-&gt;plat-&gt;force_sf_dma_mode || priv-&gt;plat-&gt;tx_coe) {
		txmode = SF_DMA_MODE; rxmode = SF_DMA_MODE;
		priv-&gt;xstats.threshold = SF_DMA_MODE;
	} <span class="hljs-keyword">else</span> {
		txmode = tc; rxmode = SF_DMA_MODE; <span class="hljs-comment">// RX 通常 SF</span>
	}
	<span class="hljs-keyword">for</span> (chan ...)
		stmmac_dma_rx_mode(..., rxmode, ...);
		stmmac_set_dma_bfsize(..., priv-&gt;dma_buf_sz, ...);
	<span class="hljs-keyword">for</span> (chan ...)
		stmmac_dma_tx_mode(..., txmode, ...);
}
</div></code></pre>
<p>DMA 通道与尾指针（Tail Pointer）更新：</p>
<ul>
<li>初始化时：
<ul>
<li>RX：<code>stmmac_init_rx_chan(..., rx_q-&gt;dma_rx_phy, chan)</code>；然后设置 <code>rx_tail_addr = dma_rx_phy + ring_size * sizeof(desc)</code> 并写 <code>stmmac_set_rx_tail_ptr()</code>。</li>
<li>TX：<code>stmmac_init_tx_chan(..., tx_q-&gt;dma_tx_phy, chan)</code>；初始化 <code>tx_tail_addr = dma_tx_phy</code> 并写 <code>stmmac_set_tx_tail_ptr()</code>。</li>
</ul>
</li>
<li>运行时：
<ul>
<li>TX 发送后，<code>tx_tail_addr = dma_tx_phy + cur_tx * desc_size</code>，写 TPDR 推进 DMA 拉取；</li>
<li>RX 回填后，<code>rx_tail_addr = dma_rx_phy + dirty_rx * sizeof(desc)</code>，写 RPDR 让 DMA 知道可用空间。</li>
</ul>
</li>
</ul>
<p>AXI 配置（<code>stmmac_axi()</code>）常见参数：固定突发、最大突发长度（PBL）、读/写 outstanding，影响带宽与仲裁效果——需要按 SoC 总线能力调优。</p>
<h3 id="%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%BA%E5%BA%8Fmermaid">初始化顺序（Mermaid）</h3>
<pre class="hljs"><code><div>flowchart TD
	I0[probe]
	I1[stmmac_hw_init]
	I2[get_hw_features]
	I3[alloc_dma_desc_resources]
	I4[stmmac_hw_setup]
	I5[dma_init + 绑定 ring 基址/尾指针]
	I6[core_init + MTL 配置]
	I7[PTP 初始化 + MMC 计数]
	I8[start_all_dma]
	I9[request_irq + 启动队列]
	I0 --&gt; I1 --&gt; I2 --&gt; I3 --&gt; I4 --&gt; I5 --&gt; I6 --&gt; I7 --&gt; I8 --&gt; I9
</div></code></pre>
<hr>
<h2 id="%E7%AC%AC-6-%E7%AB%A0%E6%8F%8F%E8%BF%B0%E7%AC%A6%E4%B8%8E%E9%98%9F%E5%88%97%E7%AE%A1%E7%90%86dwmac4descsc">第 6 章：描述符与队列管理（dwmac4_descs.c）</h2>
<p>DWMAC4 描述符提供了丰富的状态与功能位，驱动通过 <code>stmmac_desc_ops</code> 统一访问：</p>
<ul>
<li>TX：<code>prepare_tx_desc()</code>、<code>set_tx_ic()</code>、<code>enable_tx_timestamp()</code>、<code>set_mss()</code>（TSO）、<code>set_desc_vlan_tag()</code>（VLAN CTAG/STAG，双 VLAN 可选）、<code>set_desc_sarc()</code>（源地址插入策略）。</li>
<li>RX：<code>rx_status()</code>、<code>get_rx_frame_len()</code>、<code>rx_extended_status()</code>、<code>get_rx_header_len()</code>（Split Header）。</li>
<li>地址：<code>set_desc_addr()</code>/<code>get_desc_addr()</code>，必要时处理 64bit 地址。</li>
</ul>
<p>举例：在 <code>stmmac_xmit()</code> 中使用这些 ops 准备首个 TX 描述符并设置 OWN：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_xmit（节选）</span>
first = desc;
...
<span class="hljs-keyword">if</span> (has_vlan)
	stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
...
stmmac_set_desc_addr(priv, first, des);
...
stmmac_prepare_tx_desc(priv, first, <span class="hljs-number">1</span>, nopaged_len,
			csum_insertion, priv-&gt;mode, <span class="hljs-number">0</span>, last_segment,
			skb-&gt;m_len);
...
stmmac_set_tx_owner(priv, first);
arch_wmb(); <span class="hljs-comment">// OWN 必须最后写</span>
</div></code></pre>
<p>RX 回填逻辑在 <code>stmmac_rx_refill()</code>：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_rx_refill（节选）</span>
stmmac_set_desc_addr(priv, p, buf-&gt;addr);
<span class="hljs-keyword">if</span> (priv-&gt;sph)
	stmmac_set_desc_sec_addr(priv, p, buf-&gt;sec_addr, <span class="hljs-literal">true</span>);
...
arch_wmb();
stmmac_set_rx_owner(priv, p, use_rx_wd);
</div></code></pre>
<p>描述符关键字段（DWMAC4 概念梳理，结合 <code>dwmac4_descs.c</code>）：</p>
<ul>
<li>OWN：0=CPU，1=DMA；CPU 准备好后最后写 1 交给 DMA；</li>
<li>FS/LS：帧起始/结束，跨描述符的帧需要拼接；</li>
<li>CIC：Checksum Insert Control（TX）— 选择 L3/L4 校验插入模式；</li>
<li>TSE：TSO 使能位（上下文或数据描述符结合使用，按实现）；</li>
<li>Timestamp：TX 需设置使能位，RX 侧在状态中给出并由 <code>get_rx_hwtstamp()</code> 解析；</li>
<li>Error bits：如 CRC、长度、溢出等，<code>rx_status/tx_status</code> 会解析统计。</li>
</ul>
<p>模式差异：普通描述符 vs 扩展描述符（增强地址、二级缓冲/Split Header 支持），驱动通过 <code>priv-&gt;extend_desc</code> 选择相应分支。</p>
<hr>
<h2 id="%E7%AC%AC-7-%E7%AB%A0%E5%8F%91%E9%80%81%E8%B7%AF%E5%BE%84-txstmmacxmit">第 7 章：发送路径 Tx（stmmac_xmit）</h2>
<p>发送主路径在 <code>stmmac_xmit()</code>：</p>
<ul>
<li>选择队列并获得 <code>tx_q</code>；</li>
<li>处理 VLAN 插入；</li>
<li>判断是否 jumbo（在增强描述符下支持）；</li>
<li>映射首段 skb 数据，填写首个描述符；</li>
<li>依据合并策略决定是否设置 IC（Interrupt on Completion）；</li>
<li>OWN=1 移交 DMA，写 Tail Pointer，必要时启动 DMA 发送；</li>
</ul>
<p>关键片段：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_xmit（节选）</span>
<span class="hljs-keyword">if</span> (!priv-&gt;tx_coal_frames)
	set_ic = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tx_packets &gt; priv-&gt;tx_coal_frames)
	set_ic = <span class="hljs-literal">true</span>;
...
<span class="hljs-keyword">if</span> (set_ic) {
	stmmac_set_tx_ic(priv, desc);
	priv-&gt;xstats.tx_set_ic_bit++;
}
...
<span class="hljs-comment">// map + prepare + OWN</span>
stmmac_set_desc_addr(priv, first, des);
...
stmmac_prepare_tx_desc(priv, first, <span class="hljs-number">1</span>, nopaged_len, ...);
...
stmmac_set_tx_owner(priv, first);
arch_wmb();
...
stmmac_enable_dma_transmission(priv, priv-&gt;ioaddr);
...
stmmac_set_tx_tail_ptr(priv, priv-&gt;ioaddr, tx_q-&gt;tx_tail_addr, <span class="hljs-built_in">queue</span>);
</div></code></pre>
<blockquote>
<p>备注：TSO/TBS 分支在你的版本中以 <code>#if 0</code> 屏蔽，如果目标平台支持，可按需开启与补全。</p>
</blockquote>
<p>发送路径契约（inputs/outputs/错误）：</p>
<ul>
<li>输入：<code>skb</code>（可能带 VLAN tag、可能请求 HW Tx timestamp、可能 GSO）；</li>
<li>输出：把必要的缓冲映射为 DMA 地址，准备 1 个或多个描述符，设置 OWN，更新 Tail，返回 <code>NETDEV_TX_OK</code> 或 <code>NETDEV_TX_BUSY</code>；</li>
<li>错误：DMA 映射失败需 <code>dev_kfree_skb()</code> 并统计 <code>tx_dropped</code>，避免泄漏；ring 空间不足要停队列并返回 Busy。</li>
</ul>
<p>易错点与优化：</p>
<ul>
<li>OWN 必须最后写入（配合 <code>wmb/arch_wmb</code>）；</li>
<li>合理设置 IC 位降低中断风暴；</li>
<li>GSO/TSO 需要先设置 MSS（context 描述符），并注意与 TBS 互斥（见 <code>stmmac_hw_setup()</code> TSO/TBS 互斥逻辑）。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-8-%E7%AB%A0%E6%8E%A5%E6%94%B6%E8%B7%AF%E5%BE%84-rx-%E4%B8%8E-napistmmacrx">第 8 章：接收路径 Rx 与 NAPI（stmmac_rx）</h2>
<p>核心流程在 <code>stmmac_rx()</code>，由 NAPI 轮询驱动：</p>
<ol>
<li>读取当前 <code>cur_rx</code> 描述符；</li>
<li>若 DMA OWN 仍在，则退出轮询；</li>
<li>读取 <code>rx_status()</code>，收集是否分段、错误与长度；</li>
<li>计算 buf1/buf2（Split Header）长度，剥离 FCS；</li>
<li>拼装 SKB、设置时间戳与 VLAN；</li>
<li><code>napi_gro_receive()</code> 上交协议栈；</li>
<li>回填描述符并写 Tail；</li>
</ol>
<p>片段示意：</p>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_rx（节选）</span>
status = stmmac_rx_status(priv, &amp;priv-&gt;dev-&gt;stats, &amp;priv-&gt;xstats, p);
<span class="hljs-keyword">if</span> (unlikely(status &amp; dma_own))
	<span class="hljs-keyword">break</span>; <span class="hljs-comment">// DMA 仍持有</span>
...
<span class="hljs-keyword">if</span> (likely(!(status &amp; rx_not_ls))) {
	<span class="hljs-comment">// last segment，剥 FCS</span>
	<span class="hljs-keyword">if</span> (buf2_len) buf2_len -= ETH_FCS_LEN; <span class="hljs-keyword">else</span> buf1_len -= ETH_FCS_LEN;
	len -= ETH_FCS_LEN;
}
...
stmmac_get_rx_hwtstamp(priv, p, np, skb);
stmmac_rx_vlan(priv-&gt;dev, skb);
...
napi_gro_receive(&amp;ch-&gt;rx_napi, skb);
...
stmmac_rx_refill(priv, <span class="hljs-built_in">queue</span>); <span class="hljs-comment">// 回填并写 Tail</span>
</div></code></pre>
<blockquote>
<p>你的版本中 TX NAPI 清理路径与部分校验/哈希处理被 <code>#if 0</code> 掉（例如 <code>skb-&gt;ip_summed = CHECKSUM_UNNECESSARY;</code>），这在面向 VMM/移植场景下很常见。作为读者，理解“标准路径该做什么”即可。</p>
</blockquote>
<p>NAPI 绑定：</p>
<ul>
<li><code>stmmac_napi_add()</code> 为每个通道（RX/TX）添加 NAPI（本版本 TX NAPI 关闭），并在 poll 中调用 <code>stmmac_rx()</code>；</li>
<li>RX 轮询预算 <code>budget</code> 控制一次处理的包数，未耗尽预算则可在 poll 结束时 re-enable DMA IRQ。</li>
</ul>
<p>边界情况：</p>
<ul>
<li>RX 长帧跨多个描述符：通过 FS/LS 与累计 <code>len</code> 进行拼包；</li>
<li>Split Header：首描述符仅 header，次缓冲承载 payload；</li>
<li>错误帧：丢弃并统计；</li>
<li>回填失败：可能导致 ring 可用减少，需结合 <code>page_pool</code>（若启用）与内存压力处理策略。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-9-%E7%AB%A0%E4%B8%AD%E6%96%AD%E5%A4%84%E7%90%86%E4%B8%8E%E8%B0%83%E5%BA%A6stmmacinterrupt-dma-irq">第 9 章：中断处理与调度（stmmac_interrupt, DMA IRQ）</h2>
<p>主中断 <code>stmmac_interrupt()</code>：</p>
<ul>
<li>过滤 DOWN/安全特性致命错误；</li>
<li>处理 GMAC/MTL 核心中断（如 LPI 进入/退出、PCS 链路）；</li>
<li>遍历队列读取 MTL IRQ 状态；</li>
<li>调用 <code>stmmac_dma_interrupt()</code> 进一步处理各 DMA channel（错误处理、NAPI 调度等）。</li>
</ul>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_interrupt（节选）</span>
<span class="hljs-keyword">if</span> (test_bit(STMMAC_DOWN, &amp;priv-&gt;state))
	<span class="hljs-keyword">return</span> IRQ_HANDLED;
<span class="hljs-keyword">if</span> (stmmac_safety_feat_interrupt(priv))
	<span class="hljs-keyword">return</span> IRQ_HANDLED;
...
status = stmmac_host_irq_status(priv, priv-&gt;hw, &amp;priv-&gt;xstats);
...
<span class="hljs-comment">/* PCS link status */</span>
<span class="hljs-keyword">if</span> (priv-&gt;hw-&gt;pcs) {
	<span class="hljs-keyword">if</span> (priv-&gt;xstats.pcs_link) netif_carrier_on(dev);
	<span class="hljs-keyword">else</span> netif_carrier_off(dev);
}
...
stmmac_dma_interrupt(priv);
</div></code></pre>
<p>DMA 中断在 <code>stmmac_dma_interrupt()</code> 中合并处理：</p>
<ul>
<li>读取每通道 <code>stmmac_dma_interrupt_status()</code>；</li>
<li>若遇到 <code>tx_hard_error_bump_tc</code>，尝试提高阈值（从 SF 切回阈值模式的一种调节策略）；</li>
<li>若 <code>tx_hard_error</code>，调用 <code>stmmac_tx_err()</code> 停止/清空/重启该通道。</li>
</ul>
<p>与 NAPI 的配合（典型形态）：</p>
<ul>
<li>进中断只做最轻量的工作：记录状态、关对应方向 DMA IRQ，并唤醒 NAPI；</li>
<li>NAPI 轮询处理完包后再开 IRQ；</li>
<li>你的版本中这部分典型代码用 <code>#if 0</code> 保留，便于在不同运行环境下调节。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-10-%E7%AB%A0%E7%A1%AC%E4%BB%B6%E6%97%B6%E9%97%B4%E6%88%B3%E4%B8%8E-ptpstmmacptpc">第 10 章：硬件时间戳与 PTP（stmmac_ptp.c）</h2>
<p>PTP 支持通过 <code>stmmac_init_tstamp_counter()</code>、<code>stmmac_init_ptp()</code>、<code>stmmac_ptp_register()</code> 组合实现：</p>
<ul>
<li>配置 Sub-second Increment、Addend、初始系统时间；</li>
<li>提供 <code>adjfreq/adjtime/get/settime</code> 与灵活 PPS 输出；</li>
<li>TX/RX 时间戳分别在 <code>stmmac_enable_tx_timestamp()</code> 与 <code>stmmac_get_rx_hwtstamp()</code> 路径完成。</li>
</ul>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: stmmac_hw_setup（节选）</span>
ret = stmmac_init_ptp(priv);
<span class="hljs-keyword">if</span> (ret == -EOPNOTSUPP) { ... } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!ret) stmmac_ptp_register(priv);
</div></code></pre>
<blockquote>
<p>如果硬件不支持，驱动会优雅降级（日志提示）。</p>
</blockquote>
<p>PTP 频率调节核心（Addend）的计算小抄：</p>
<p>设硬件时钟基于增量加法器，周期为 $T_{clk}$，目标频率为 $f_{ptp}$，硬件参考频率为 $f_{ref}$，则加数（addend）可按：</p>
<p>$$\text{addend} = \left\lfloor \frac{2^{32} \cdot f_{ptp}}{f_{ref}} \right\rfloor$$</p>
<p>子秒增量（sub-second increment）与时钟周期关系：若每个周期增加 $inc$ 个子秒单位，子秒分辨率为 $2^{31}$（示意，具体视实现），则：</p>
<p>$$inc = \left\lceil \frac{2^{31}}{f_{ptp}} \cdot f_{clk} \right\rceil$$</p>
<p>实际实现以 <code>stmmac_init_tstamp_counter()</code> 中的寄存器定义为准，驱动会依据平台/参考时钟求解合适的参数并写入，随后通过 <code>adjfreq/adjtime</code> 微调。</p>
<hr>
<h2 id="%E7%AC%AC-11-%E7%AB%A0mdiophy-%E7%AE%A1%E7%90%86stmmacmdioc-stmmacinitphy">第 11 章：MDIO/PHY 管理（stmmac_mdio.c, stmmac_init_phy）</h2>
<ul>
<li>MDIO 总线读写支持 GMAC4 与 XGMAC2，兼容 Clause 22/45；</li>
<li>提供 <code>stmmac_mdio_register()</code>/<code>_unregister()</code> 工具，<code>stmmac_init_phy()</code> 负责 attach PHY；</li>
<li>MII 时钟 <code>clk_csr</code> 可静态指定或运行时基于 <code>stmmac_clk_csr_set()</code> 动态计算。</li>
</ul>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_mdio.c（示意）</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">stmmac_mdio_read</span><span class="hljs-params">(...)</span> </span>{ <span class="hljs-comment">/* 轮询忙位、写入地址、取数 */</span> }
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">stmmac_mdio_write</span><span class="hljs-params">(...)</span> </span>{ <span class="hljs-comment">/* 轮询忙位、写入数据 */</span> }
</div></code></pre>
<p>关键时序与超时：</p>
<ul>
<li>访问 MDIO 前先确认 <code>BUSY</code> 清零，写指令后等待完成或超时返回；</li>
<li>Clause 45 需要分两步（地址相位 + 数据相位）；</li>
<li>MII 时钟分频 CSR 需符合 PHY 规范（例如不超 2.5MHz），<code>stmmac_clk_csr_set()</code> 会按输入时钟动态选最优分频档位。</li>
</ul>
<p>PHY 管理：<code>stmmac_init_phy()</code> 负责 attach PHY，与 phylib 协作管理自协商、速率/双工、pause 能力等；PCS 模式下还会经由 <code>stmmac_pcs_*</code> 接口控制。</p>
<hr>
<h2 id="%E7%AC%AC-12-%E7%AB%A0eeevlanrsstctsotbs-%E7%AD%89%E8%BF%9B%E9%98%B6%E8%83%BD%E5%8A%9B">第 12 章：EEE/VLAN/RSS/TC/TSO/TBS 等进阶能力</h2>
<ul>
<li>EEE：<code>stmmac_eee_init()</code>、<code>stmmac_enable_eee_mode()</code>、LPI 进入/退出与控制定时器；</li>
<li>VLAN：VLAN 插入（TX）、VLAN 过滤（RX Hash/精确匹配，硬件支持时）；</li>
<li>RSS：在 <code>stmmac_mac_config_rss()</code> 开启并配置哈希密钥与重定向表；</li>
<li>TC：CBS/ETF/TAPRIO 等通过 <code>stmmac_tc_ops</code>；</li>
<li>TSO/TBS：DWMAC4 起支持，本文版本中屏蔽了 TSO/TBS 示例分支，可按硬件与内核版本恢复；</li>
<li>Split Header（SPH）：降低内存压力、提升 GRO 合并效果。</li>
</ul>
<blockquote>
<p>这些能力是否可用取决于 <code>dma_cap</code> 与平台参数；初始化阶段会统一判定并“只做可做的事”。</p>
</blockquote>
<p>几个易混概念：</p>
<ul>
<li>EEE 与 LPI：EEE 是协议能力，LPI 是进入低功耗状态的具体动作；TX 进入 LPI 时，驱动会记录 <code>tx_path_in_lpi_mode</code> 并在中断中更新；</li>
<li>VLAN 过滤模式：Hash vs 精确匹配（硬件寄存器位宽有限，Hash 模式可容纳更多但有碰撞风险）；</li>
<li>RSS：需要硬件支持+平台开启，驱动会填充默认重定向表与随机 key，可通过 ethtool 调整（若使能）。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-13-%E7%AB%A0%E8%B0%83%E8%AF%95%E4%B8%8E%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8Ddebugfsmmc-%E8%AE%A1%E6%95%B0%E5%99%A8%E5%B8%B8%E8%A7%81%E9%99%B7%E9%98%B1">第 13 章：调试与问题定位（DebugFS、MMC 计数器、常见陷阱）</h2>
<ul>
<li>DebugFS：<code>/sys/kernel/debug/stmmac/&lt;ifname&gt;/</code> 提供 ring 转储与 DMA 能力显示：</li>
</ul>
<pre class="hljs"><code><div><span class="hljs-comment">// stmmac_main.c: debugfs 展示（节选）</span>
DEFINE_SHOW_ATTRIBUTE(stmmac_rings_status);
DEFINE_SHOW_ATTRIBUTE(stmmac_dma_cap);
</div></code></pre>
<ul>
<li>MMC 计数器：<code>stmmac_mmc_setup()</code> 初始化并在软件中维护统计；</li>
<li>常见陷阱：
<ul>
<li>OWN 位写序必须最后（<code>wmb()/arch_wmb()</code>），否则 DMA 可能看到不一致；</li>
<li>尾指针需要与 <code>cur_tx/dirty_rx</code> 协同更新，避免 ring“断链”；</li>
<li>SF/阈值模式切换要考虑 TX COE/Jumbo 兼容性；</li>
<li>MDIO CSR 时钟要匹配平台时钟，否则读写失败；</li>
<li>NAPI/IRQ 互斥与使能/禁止时序。</li>
</ul>
</li>
</ul>
<p>定位思路建议：</p>
<ul>
<li>“不收包”：检查 RX IRQ 是否触发、<code>stmmac_rx()</code> 是否被调用、<code>rx_status</code> 是否总是 OWN、回填路径是否正确写回 OWN 与 Tail；</li>
<li>“不发包”：检查 <code>stmmac_xmit()</code> 是否成功映射并置 OWN，<code>stmmac_enable_dma_transmission()</code> 调用、TX Tail 是否前进、DMA 错误中断是否上报；</li>
<li>“建链异常”：核对 MDIO CSR 分频、PHY 地址、Clause22/45 匹配、PCS 配置、时钟/复位是否拉起；</li>
<li>“时间戳错”：确认 <code>stmmac_init_tstamp_counter()</code> 配置、RX/TX 是否开启 TS、读写寄存器后是否有足够时间稳定、频率/offset 调整接口是否被正确调用。</li>
</ul>
<hr>
<h2 id="%E9%99%84%E5%BD%95%E7%BB%A7%E7%BB%AD%E9%98%85%E8%AF%BB%E4%B8%8E%E6%BA%90%E7%A0%81%E8%B7%B3%E8%BD%AC">附录：继续阅读与源码跳转</h2>
<ul>
<li>主干：<code>stmmac_main.c</code>（生命周期、收发路径、IRQ/NAPI/服务任务）；</li>
<li>平台：<code>stmmac_platform.c</code>（DT/资源/队列/AXI/MTL）；</li>
<li>抽象：<code>hwif.h</code>（ops 表与调用分发）；</li>
<li>MAC：<code>dwmac4_core.c</code>；DMA：<code>dwmac4_dma.c / dwmac4_lib.c</code>；</li>
<li>描述符：<code>dwmac4_descs.c</code>；</li>
<li>时间戳/PTP：<code>stmmac_ptp.c</code>；</li>
<li>MDIO/PHY：<code>stmmac_mdio.c</code>。</li>
</ul>
<hr>
<h2 id="%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B%E4%B8%8E%E9%98%85%E8%AF%BB%E6%8C%87%E5%BC%95">快速上手与阅读指引</h2>
<p>目标：最快跑通 + 按需深入。</p>
<ul>
<li>三步起网：
<ol>
<li>设备树最小化（第 2 章模板），确认 phy-mode/时钟/复位；</li>
<li>观察 probe 日志与建链（第 31 章清单）；</li>
<li>基线压测与中断/延迟观测（第 24/36 章）。</li>
</ol>
</li>
<li>要点索引：
<ul>
<li>架构/路径总览：第 1 章（两张总览图）；</li>
<li>初始化顺序：第 5 章图；</li>
<li>TX/RX 细节：第 7/8 章 + 第 14 章序列图；</li>
<li>SoC glue：Rockchip 第 27 章、DWC QoS 第 28 章；</li>
<li>问题定位：第 13/20/25/26 章；</li>
<li>TSN/PTP：第 34/38 章；</li>
<li>速查：第 40 章；</li>
</ul>
</li>
<li>若需板级定制：参考第 22 章 DT 示例 + 第 27 章平台要点。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-14-%E7%AB%A0%E4%BB%8E%E4%B8%BB%E5%B9%B2%E5%88%B0%E7%BB%86%E8%8A%82%E7%9A%84%E5%85%A8%E8%B7%AF%E5%BE%84-walkthroughtx-%E4%B8%8E-rx-%E9%80%90%E6%AD%A5%E6%8B%86%E8%A7%A3">第 14 章：从主干到细节的全路径 Walkthrough（TX 与 RX 逐步拆解）</h2>
<pre><code>这一章把“从发包到收包”的关键步骤串成一条完整链路，帮助你在脑中建立“函数栈 + 硬件状态机 + 队列/描述符”的三视图模型。

### 14.1 发送路径（TX）逐步图解

前提：netdev 已注册，`ndo_open` 完成了 MAC/DMA/MTL 初始化，队列启动成功。

1) 上层协议栈调用 `ndo_start_xmit = stmmac_xmit(skb, dev)`：
	- 决定队列：`u32 queue = skb_get_queue_mapping(skb)`，取对应 `stmmac_tx_queue`。
	- 可选 VLAN 插入：`stmmac_vlan_insert()` 在支持时追加 VLAN 描述符项（或在首描述符设置 VLAN 插入位）。
	- 选择描述符：`first = &amp;tx_q-&gt;dma_tx[first_entry]`（或 `dma_etx`/`dma_entx`）。
	- DMA 映射：`des = dma_map_single(..., skb-&gt;m_data, ...)`；失败 → 丢包并记账。
	- 填地址：`stmmac_set_desc_addr(priv, first, des)`；
	- 准备描述符：`stmmac_prepare_tx_desc(..., own=1, len, csum, mode, ... ls, skb_len)`；
	- OWN 必须最后写：`stmmac_set_tx_owner(...)` + `arch_wmb()`；
	- 刷新尾指针：`tx_q-&gt;tx_tail_addr = dma_tx_phy + cur_tx * desc_size; stmmac_set_tx_tail_ptr(...)`；
	- 启动 DMA 拉取（有的平台要求显式“kick”）：`stmmac_enable_dma_transmission(...)`。

2) 硬件拉取与发送：
	- DMA 读首个描述符，看到 OWN=1，取出 Buffer 地址与长度；
	- MAC 发包；如使能 Timestamp，会在写回时在描述符状态中填入时间戳。

3) 完成与清理：
	- 经典路径中，TX NAPI 或定时器会触发 `stmmac_tx_clean()`，
	  解析 `tx_status`，释放 DMA 映射与 skb（只在最后一个片段上挂 skb 指针）；
	- 当 ring 空间回收超过阈值会唤醒停下的队列（`netif_tx_wake_queue`）。

边界与细节：

- GSO/TSO（如使能）：
  - 需先写 context 描述符设置 MSS（`stmmac_set_mss()`），然后按 16KB 最大分片填充多个数据描述符；
  - TSO 与 TBS 互斥（见 `stmmac_hw_setup()` 的分支）。
- VLAN 双标签（dvlan）：硬件支持时可插入 C-TAG + S-TAG；
- 校验插入（CSUM）：SF 模式更友好；若为阈值模式且 HW 限制，需谨慎；
- 队列合并（IC）：按 `tx_coal_frames` 决定，降低中断率。

### 14.2 接收路径（RX）逐步图解

1) DMA 写入数据：
	- DMA 检测 RX ring 的 OWN=1 的描述符可用；
	- 把数据写入 `buf-&gt;addr`（可选 `sec_addr` 支持 Split Header），置 FS/LS 标记、长度、错误位，最后清 OWN 给 CPU。

2) 中断/NAPI：
	- `stmmac_interrupt()` → 读取 GMAC/MTL 状态（LPI/PCS/队列），调用 `stmmac_dma_interrupt()`；
	- 通常会调度 NAPI（本版本部分路径以 `#if 0` 形式保留模板逻辑）。

3) `stmmac_rx()` 轮询：
	- 检查 `dma_own`；未交还则退出；
	- 解析 `rx_status()`，判断错误/分片；
	- 计算 buf1_len/buf2_len（SPH）、剥离 FCS；
	- 组装 SKB，处理硬件时间戳/哈希/VLAN；
	- `napi_gro_receive()` 上交协议栈；
	- `stmmac_rx_refill()` 回填新 OWN=1 的描述符，刷新 `rx_tail_addr`。

4) RX 合并与 Watchdog：
	- 如果开启 `use_riwt`，可通过 RIWT 合并中断；
	- 也可通过软件 coalesce（rx_coal_frames）做细粒度控制。

常见问题：

- 总是 OWN=DMA：说明回填不正确或 DMA 没被使能；
- 长帧被截断：检查 FS/LS 拼包逻辑、bfsize、MTU/FIFO；
- 校验相关：`rx_ipc` 关闭时，上层需自行校验 `CHECKSUM_NONE`；
- VLAN 未生效：确认 `vlins` 能力与插入/提取路径的配置，双 VLAN 需硬件支持。

### 14.3 TX/RX 顺序图（Mermaid）

```mermaid
sequenceDiagram
  participant NS as Net Stack
  participant SM as stmmac_main
  participant HW as MAC/DMA
  participant MTL as MTL
  participant PHY as PHY/PCS

  Note over NS: TX
  NS-&gt;&gt;SM: ndo_start_xmit(skb)
  SM-&gt;&gt;SM: map + prepare descs\nset OWN, update tail
  SM-&gt;&gt;HW: enable DMA transmission
  HW-&gt;&gt;MTL: enqueue/dequeue
  MTL-&gt;&gt;HW: send frame
  HW--&gt;&gt;SM: TX status / timestamp
  SM--&gt;&gt;NS: TX complete

  Note over NS: RX
  HW-&gt;&gt;MTL: frame arrives
  MTL-&gt;&gt;HW: write to memory
  HW--&gt;&gt;SM: IRQ
  SM-&gt;&gt;SM: NAPI poll -&gt; stmmac_rx
  SM--&gt;&gt;NS: napi_gro_receive(skb)
  SM-&gt;&gt;HW: refill + update RX tail
```

---

## 第 15 章：MAC 核心操作详解（dwmac4_core.c 要点）

MAC Core 通过 `stmmac_ops` 暴露统一能力，常见包括：

- `core_init()`：配置基本 MAC 寄存器、校验路径（`rx_ipc`）、中断；
- `mac_set()`：收发开关；
- `prog_mtl_rx_algorithms()` / `prog_mtl_tx_algorithms()`：MTL 调度算法（SP/WRR/ETS 等）；
- `set_mtl_tx_queue_weight()`：加权；
- `map_mtl_to_dma()`：队列与 DMA 通道映射；
- `rx_queue_prio()` / `tx_queue_prio()`：优先级；
- `rx_queue_routing()`：包类型到队列路由（广播/多播/优先级匹配等）；
- 流控：`flow_ctrl()`、`pmt()`（远程唤醒）、`enable_eee()`、`set_eee_timer()`；
- VLAN：开启/Hash 过滤/精确匹配表项数量的维护；
- 过滤器：L3/L4 过滤、ARP Offload、VLAN Fail Queue 等。

实践建议：

- 多队列性能：开启 RSS 并设置合理的 RX routing，结合 GRO 减少协议栈开销；
- 流控策略：若对延迟敏感且对丢包容忍低，可启用对称 pause，但注意与对端匹配；
- VLAN：Hash 模式可容纳更多 VLAN，但存在碰撞风险；
- Debug：`dwmac4_core.c` 中的调试寄存器读出方法有助于定位堵塞点。

---

## 第 16 章：VLAN/过滤/RSS 的硬件协同

### 16.1 VLAN

- TX 插入：在 `stmmac_xmit()` 中通过 `stmmac_set_desc_vlan_tag()` 或 `stmmac_set_desc_vlan()`；
- RX 过滤：
  - Hash 过滤（`vlhash` 能力）：根据 VID 计算 CRC 高位作为索引；
  - 精确匹配：受限于硬件表项数；
  - 双 VLAN（`dvlan`）：C-TAG + S-TAG 支持；
- VLAN Fail Queue：不匹配的 VLAN 可被路由到特定队列（`vlan_fail_q_en`）。

### 16.2 过滤器（L3/L4/ARP offload）

- L3/L4：可把特定 IP/端口组合的流引到指定队列或丢弃；
- ARP Offload：硬件响应 ARP，减轻 CPU 负担（需正确配置 MAC/IP）。

### 16.3 RSS

- 需硬件 `rssen` 能力 + 平台 `rss_en`；
- 驱动在 probe 时填充随机 key 与默认重定向表；
- 运行时可通过 ethtool 修改，验证报文哈希与队列分布；
- 与 GRO 协同提升吞吐，注意小包 PPS 与缓存亲和。

---

## 第 17 章：PTP/IEEE 1588 细节补充

函数族（`stmmac_ptp.c`）：

- `stmmac_init_tstamp_counter()`：设置 sub-second increment、addend、初始系统时间；
- `stmmac_adjust_freq()`、`stmmac_adjust_time()` 对应内核的 `adjfreq/adjtime`；
- `stmmac_get_time()` / `stmmac_set_time()`：PHC 读写；
- `stmmac_ptp_register()` / `stmmac_ptp_unregister()`：注册/注销 PTP 时钟；
- PPS/外部时间戳输入（若硬件支持）。

RX/TX 时间戳：

- TX：在 `stmmac_xmit()` 对首描述符设置 TX TS 使能；完成时在回写状态中带上时间戳；
- RX：`stmmac_get_rx_hwtstamp()` 从 RX 描述符解析并填入 skb；

### PTP 硬件时间戳流程（Mermaid）

```mermaid
sequenceDiagram
	participant CPU as CPU
	participant MAC as MAC
	participant DMA as DMA
	participant Desc as 描述符
	participant PHC as PTP 硬件时钟

	CPU-&gt;&gt;MAC: 发送帧请求 (TX)
	MAC-&gt;&gt;DMA: 写入描述符 OWN=1
	DMA-&gt;&gt;MAC: 拉取帧
	MAC-&gt;&gt;PHC: 记录 TX 时间戳
	PHC--&gt;&gt;Desc: 写入描述符时间戳字段
	Desc--&gt;&gt;CPU: 回收时读取时间戳

	Note over MAC,PHC: RX 路径同理，MAC 收到帧时写入 RX 描述符
```

频率与子秒增量的关系前文已用公式给出。实际部署建议：

- 先校对基频（addend/sub-second），再通过 `adjfreq` 微调；
- 长期稳定性取决于参考时钟（板级晶振/PLL）；
- 高精度场景应关注 SoC 时钟域抖动与温漂。

---

## 第 18 章：MDIO/PHY/PCS 的完整路径

### 18.1 MDIO 访问概述

- Clause 22：5-bit PHY addr + 5-bit reg；
- Clause 45：设备地址 + 寄存器地址，分两相位（地址相位+数据相位）；
- CSR 时钟：MDC 不超过 PHY 规范（一般 2.5MHz），用 `stmmac_clk_csr_set()` 动态选择档位。

时序守则：

- 每次发起前轮询 `BUSY` 清零；
- 写入命令后等待完成，超时返回错误；

### MDIO Clause 22/45 访问流程（Mermaid）

```mermaid
flowchart TD
	subgraph C22[Clause 22]
		A1[CPU 发起读/写]
		A2[写 PHY addr + reg]
		A3[轮询 BUSY]
		A4[读/写数据]
	end
	subgraph C45[Clause 45]
		B1[CPU 发起读/写]
		B2[写 PHY addr + dev addr + reg addr (地址相位)]
		B3[轮询 BUSY]
		B4[写/读数据 (数据相位)]
		B5[轮询 BUSY]
	end
	A1 --&gt; A2 --&gt; A3 --&gt; A4
	B1 --&gt; B2 --&gt; B3 --&gt; B4 --&gt; B5
```
- `stmmac_mdio_register()` 会创建并注册 `mdiobus`，扫描/登记 PHY，并在 `stmmac_init_phy()` attach。

### 18.2 PCS/SerDes 协作

- 若走 SGMII/1000Base-X/10GBase-R 等，需要经 PCS 配置链路模式与速率；
- `stmmac_pcs_ctrl_ane()` 可设置自协商与速率提示；
- 平台 `serdes_powerup/powerdown` 回调可在 probe/remove 时机执行上电/下电序列。

---

## 第 19 章：能效与拥塞控制（EEE、流控、合并）

- EEE：
  - `stmmac_eee_init()`、`stmmac_enable_eee_mode()`、`eee_ctrl_timer` 控制 LPI 进出；
  - `tx_path_in_lpi_mode` 在中断中更新；
- 流控（Pause）：
  - RX/TX 对称或单向，取决于对端协商与策略；
  - 拥塞高发场景可适当开启，但对延迟有影响；
- 合并（Coalesce）：
  - 硬件 RIWT（RX Watchdog） + 软件 coalesce（tx_coal_frames/rx_coal_frames）；
  - 调参与业务负载特征强相关，需要实测权衡中断数、延迟与吞吐。

---

## 第 20 章：常见集成问题与 Checklist

- 资源与时钟：寄存器基址、IRQ、复位/时钟是否上电；`pm_runtime`/时钟域是否活跃；
- MDIO：CSR 分频、GPIO reset、C22/C45 模式匹配、PHY 地址有效；
- PCS：接口模式与速率、AN 使能与对端一致；
- DMA：PBL/FB/AXI 参数与总线匹配，EAME（扩展地址）与 IOMMU/地址宽度一致；
- 队列：MTL 到 DMA 映射、权重/算法、RSS 表；
- 描述符与缓存一致性：OWN 写序、`dma_sync_*` 使用、缓存属性；
- 特性：TSO/TBS/EEE/VLAN/RSS 等是否与硬件能力对齐；
- 调试入口：DebugFS、MMC counters、寄存器 dump、ethtool 统计。

---

## 附录 A：术语速查

- DWMAC/XGMAC：Synopsys 以太网 MAC IP 家族；
- MTL：MAC 传输层队列调度与路由；
- DMA：内存访问引擎，负责搬运描述符与数据；
- OWN/FS/LS：描述符所有权、帧起始/结束标志；
- RIWT：RX Interrupt Watchdog 定时器；
- SPH：Split Header；
- TSO/TBS：大报文分段卸载/基于时间的调度；
- PBL：Programmable Burst Length；
- PCS：Physical Coding Sublayer；
- PHC：PTP 硬件时钟。

## 附录 B：寄存器与位含义速览（方向性提示）

以下为调试/阅读时常用的寄存器与其作用（以 DWMac4 为例，名称以源码注释为准）：

- DMA 控制/状态：软复位、通道 enable、TPDR/RPDR；
- MTL 队列：调度算法、权重、映射与状态；
- MAC 配置：收发开关、速率、校验、VLAN、过滤器、EEE；
- PTP：Addend、Sub-second increment、System time；
- MMC：统计计数器控制/状态；
- MDIO：C22/C45 命令与数据寄存器、BUSY 位。

&gt; 实际位定义需结合你平台对应的头文件/手册；本文以逻辑为主，避免与不同内核版本寄存器命名差异引起误解。

---

# 结语

至此，我们从架构到实现、从初始化到收发、中断与时间戳、再到 VLAN/RSS/EEE/TSO/TBS 等进阶能力，结合你仓库中的 stmmac 代码，完整梳理了一条“可验证、可落地”的驱动学习路径。下一步建议结合目标板做参数调优（AXI/PBL/合并/流控/队列策略），并针对你的业务场景（低时延/高吞吐/节能/确定性）各自找到最佳点。

---

## 第 21 章：TSO/TBS 描述符流水线（DWMAC4 版本）

本章以逻辑层面讲解 TSO（大报文分段卸载）与 TBS（基于时间调度）在 DWMAC4 的典型描述符序列。你的源码中 TSO/TBS 路径以 `#if 0` 屏蔽，实际平台支持时可参考如下要点复原。

### 21.1 TSO（TCP/UDP 分段卸载）

- 背景：将一个大包按 MSS 自动分段，硬件生成多个线速片段，降低 CPU 开销；
- 关键元素：
	- MSS 设置：使用 Context Descriptor 写入 `MSS`（`stmmac_set_mss()`）；
	- 首描述符：指向 L2/L3/L4 头部（`proto_hdr_len`）；
	- 后续描述符：覆盖 payload，可能拆分到多个描述符；
	- 完成条件：在最后一个数据描述符设置 LS；
	- 校验：硬件插入（CIC）；
- 核心注意：
	- OWN 写序：Context 的 OWN 通常要在首数据描述符最终写入后再置位，确保硬件看到一致顺序（配合 `dma_wmb()`）；
	- 描述符预算：估算 `((payload_len)/16KB + 1)`；
	- 与 TBS 互斥：同一 TXQ 通常不可同时使能。

### 21.2 TBS（Time-Based Sending）

- 背景：面向 TSN/确定性网络，按绝对时间/窗口调度发送；
- 关键元素：
	- 扩展描述符中额外的秒/纳秒调度字段；
	- TXQ 需配置为支持 TBS 模式；
	- 报文的 tstamp 字段（`skb-&gt;tstamp`）转为描述符时间；
- 核心注意：
	- PHC/系统时间一致性：需要保证 MAC PTP 时钟与上层计划时间一致；
	- 延迟预算：考虑 DMA 取数、FIFO 排队与电口延迟，适度提早调度；
	- 溢出与回绕：描述符时间戳字段宽度导致的边界条件需要防护（时间窗口对齐）。

---

## 第 22 章：设备树（DT）与平台集成 Cookbook（示例与要点）

以下示例为抽象化模板，具体属性名/兼容字符串以你的 SoC 文档为准。

示例：RGMII + 外部 PHY，千兆模式，2 RX/2 TX 队列，开启 RSS。

```dts
ethernet@fe000000 {
	compatible = &quot;vendor,soc-dwmac4&quot;;
	reg = &lt;0x0 0xfe000000 0x0 0x10000&gt;;
	interrupts = &lt;GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH&gt;;
	phy-mode = &quot;rgmii-id&quot;;
	phy-handle = &lt;&amp;phy0&gt;;
	clocks = &lt;&amp;clk STMMAC_CLK&gt;, &lt;&amp;clk PCLK&gt;, &lt;&amp;clk PTP_REF&gt;;
	clock-names = &quot;stmmaceth&quot;, &quot;pclk&quot;, &quot;ptp_ref&quot;;
	resets = &lt;&amp;cru SRST_STMMAC&gt;;

	snps,mtl-queues = &lt;2 2&gt;;           // tx rx
	snps,tx-queues-cfg = &lt;0x0 0x0&gt;;     // prio/weight per queue
	snps,rx-queues-cfg = &lt;0x0 0x0&gt;;     // prio/routing per queue
	snps,axi-config = &lt;...&gt;;            // pbl/fixed-burst/awr/rwr
	snps,dma-config = &lt;...&gt;;            // pbl/fb/eame
	snps,rss-enable;

	mdio: mdio { status = &quot;okay&quot;; };
};

mdio {
	phy0: ethernet-phy@1 {
		reg = &lt;1&gt;;
		/* vendor-specific PHY tuning here */
	};
};
```

要点：

- 确认 `phy-mode` 与板级 RGMII 延时（ID）一致；
- `ptp_ref`（若有）频率要准确；
- `axi-config` 与 DDR/主总线能力匹配；
- 多队列时，队列映射与权重要结合业务流量模型。

---

## 第 23 章：ethtool 操作小抄（可验证驱动行为）

- 查看/设置合并（仅示意，具体开关受实现影响）

```bash
# 查看
ethtool -c eth0
# 设置 TX 每 N 帧触发一次中断（若支持）
ethtool -C eth0 tx-frames 64
```

- 开关 RX/TX 校验与 TSO（若平台支持）

```bash
ethtool -k eth0                  # 查看 offload 能力
ethtool -K eth0 rx on tx on tso on gro on gso on
```

- RSS/重定向表（多队列）

```bash
ethtool -x eth0                  # 查看 indir 表
ethtool -X eth0 equal 2          # 平均分配到2个 RX 队列
```

- PTP 校时（结合 ptp4l）

```bash
ptp4l -i eth0 -m -H -2           # 以硬件时间戳模式运行
phc2sys -s CLOCK_REALTIME -c /dev/ptp0 -O 0 -m
```

---

## 第 24 章：性能画像与调优策略

### 24.1 画像方法

- 观测维度：PPS、吞吐（Gbps）、平均/尾延迟、中断数、CPU 利用率、缓存命中；
- 工具：`perf`, `sar`, `mpstat`, `ethtool -S`, DebugFS 统计、自研计数器；
- 负载：
	- 小包 PPS：如 64B、IMIX；
	- 大包吞吐：1500/9000 MTU；
	- 混合流量：多流/多核压测。

### 24.2 调优抓手

- DMA/AXI：PBL、固定突发、Outstanding；
- 合并：RIWT + SW coalesce（找平衡点）；
- MTL 调度与权重：避免饥饿，匹配业务优先级；
- RSS + GRO：分散负载，增大合并粒度；
- 流控策略：在丢包与延迟之间折中；
- NUMA/中断亲和：绑定队列到核，减少跨核抖动；
- 缓冲尺寸：`dma_buf_sz`、bfsize 策略与 MTU/FIFO 的关系。

---

## 第 25 章：案例集（从症状到根因）

案例 A：发送不出包

- 症状：`tx_bytes` 不增加，`tx_dropped` 增长；
- 检查：
	- `stmmac_xmit()` 是否成功 `dma_map_single`，OWN 是否置位；
	- TX Tail 是否推进；
	- DMA 错误中断是否上报（`tx_hard_error`）；
	- AXI/PBL 配置是否异常导致总线拒绝；
- 处置：
	- 复位通道（`stmmac_tx_err()`）并捕捉寄存器快照；
	- 降低 PBL/关闭固定突发尝试；
	- 核对 IOMMU/地址宽度与 EAME 设置。

案例 B：收不到包

- 症状：`rx_packets` 静止；
- 检查：
	- `stmmac_rx_refill()` 是否把 OWN=1 写回；
	- RX Tail 是否推进；
	- 中断是否触发（`/proc/interrupts`）；
	- PCS 链路与 PHY 状态；
- 处置：
	- 关闭合并看是否恢复（避免过度合并）；
	- 检查缓存一致性/映射属性；
	- 适当缩小 `dma_buf_sz` 以排除超界。

案例 C：PTP 时间漂移大

- 检查：addend/sub-second 配置，`adjfreq` 是否生效；
- 处置：对比板载参考时钟，修正 `ptp_ref` 频率；稳定后再做微调。

---

## 第 26 章：常见问题（FAQ）

- Q：为什么有些路径在源码中被 `#if 0`？
	- A：为了适配特定运行环境（如 VMM/移植场景）或减少复杂性。理解标准路径后，可按需开启并补全。

- Q：如何判断硬件是否支持某能力？
	- A：看 `stmmac_get_hw_features()` 填充的 `dma_cap`，并结合 `plat` 的开关；probe 阶段也会打印提示。

- Q：为何偶发 TX 超时？
	- A：可能是总线拥塞、PBL 不当、阈值模式下 COE 限制或队列合并设置过激；先捕获 DMA/MMC/MTL 状态再调整参数。

---

## 附录 C：环形队列索引与内存序（公式与认知）

- 环形推进：

$$entry_{next} = (entry + 1) \bmod N$$

驱动里以 `STMMAC_GET_ENTRY` 宏实现；

- OWN 写序：

1) 填写地址/长度/标志；
2) 写屏障 $wmb()$ 或平台等效；
3) 写 OWN=1；

- RX 回填合并计数：

在 `stmmac_rx_refill()` 中，用计数和 RIWT 配合决定是否使用硬件 watchdog 中断。

---

## 附录 D：内存模型与 DMA 同步小结

- `dma_map_single/page` 后地址即可给 DMA 使用；
- 在设备写入后，CPU 读之前需要 `dma_sync_single_for_cpu`（若启用缓存）；
- 回写给设备前 `dma_sync_single_for_device`；
- OWN 位写入前需要 `wmb()`/`arch_wmb()` 保证先前字段对 DMA 可见；
- 读 OWN 后再读其它字段要 `rmb()`/`arch_rmb()`；
- 不同架构的屏障语义略有差异，以平台实现为准。

---

## 第 27 章：Rockchip 平台 glue 深入（`dwmac-rk.c` 实战）

本章针对你仓库中的 `dwmac-rk.c`，梳理 Rockchip SoC 上层“glue 层”的角色与关键路径：接口模式切换（RGMII/RMII/SGMII/QSGMII）、时钟树与延时线、集成 PHY 供电/复位、速率变化回调以及 probe/power 管理。

### 27.1 关键结构与回调表

- `struct rk_gmac_ops`：按 SoC 型号封装一组钩子（回调），用于配置 GRF/PIPE-GRF/XPCS 寄存器：
	- `set_to_{rgmii,rmii,sgmii,qsgmii}`：选择接口模式，并配置相关寄存器（含 RGMII TX/RX 延时开关与延时值）。
	- `set_{rgmii,rmii}_speed`：链路速率变化时设置分频/选择（125/25/2.5MHz 或 SGMII PCS）。
	- `set_clock_selection`：RMII 输入/CRU 输出切换与门控（如 RK3588）。
	- `integrated_phy_power`：部分 SoC 的内置 PHY 上电/掉电序列。

- `struct rk_priv_data`：保存平台资源与状态：
	- 时钟：`mac_clk_rx/tx`、`clk_mac_ref/refout/speed`、`aclk_mac/pclk_mac`、`pclk_xpcs` 等；
	- 延时线：`tx_delay`、`rx_delay`（来自 DT）；
	- GRF/XPCS/PIPE-GRF regmap；
	- `phy_iface`（`of_get_phy_mode()` 解析）与 `clock_input`（`clock_in_out` 属性）。

注意：本仓库里在 `rk_gmac_setup()` 中将 `bsp_priv-&gt;ops` 强制绑定到 `rk3568_ops`（而非按 `compatible` 动态匹配），以及 `rk_gmac_dwmac_match` 仅保留了 `&quot;rockchip,rk3568-gmac&quot;` 项。若移植到其他 SoC，请恢复按 SoC 的 `ops` 选择。

### 27.2 时钟与上电序列

- `rk_gmac_clk_init()`：按 `phy_iface` 拉取并设置相关时钟；RMII 模式下通常设 `clk_mac`=50MHz，并根据 `clock_in_out` 选择是否启用 `clk_mac_refout` 输出至 PHY。
- `gmac_clk_enable(enable)`：批量 enable/disable 所有相关时钟，并在需要时切换 RMII 时钟来源（例如 RK3588 通过 `set_clock_selection`）。
- `rk_gmac_phy_power_on(true/false)`：可选 LDO 供电控制（`regulator`）。
- `rk_gmac_powerup()`：整体电源上电序列：
	1) 使能时钟；
	2) 按 `phy_iface` 调用 `ops-&gt;set_to_*` 切换模式；
	3) 集成 PHY 时，调用 `integrated_phy_power(up)`；
	4) 启用 `pm_runtime`；
	5) 返回主驱动继续初始化。

### 27.3 接口模式与速率回调

- RGMII：配置 `*_PHY_INTF_SEL_RGMII`，并根据 `tx_delay/rx_delay` 以 HIWORD-UPDATE 写入延时线寄存器（如 `RK3568_GMAC_CLK_TX/RX_DL_CFG`）。`RGMII_ID/RXID/TXID` 情形分别将对应一侧延时设为禁用（-1）。
- RMII：写 `*_PHY_INTF_SEL_RMII` 与 `RMII_MODE`；速率切换写 `SPEED_10M/100M` 并设置 `clk_mac_speed` 为 2.5MHz/25MHz；
- SGMII/QSGMII：通过 `xpcs_setup()` 完成 PCS 的 soft reset、AN 配置与 Link Timer；
- `rk_fix_speed()`：注册为主驱动 `plat-&gt;fix_mac_speed`，当 PHY 协商到新速率时回调至此，转调 `ops-&gt;set_*_speed` 完成时钟切换；
- `dwmac_rk_set_rgmii_delayline()`/`_get_*()`：运行期读写 RGMII 延时（提供给 ethtool/私有 ioctl 使用）。

### 27.4 集成 PHY 与 MAC 地址

- 集成 PHY：读取 `phy-is-integrated` 并获取 `phy_reset` 控制器；上电/掉电序列在对应 `*_integrated_phy_power()` 中实现（不同 SoC 有差异）。
- MAC 地址：`rk_get_eth_addr()` 提供从 vendor storage 读取的逻辑（当前用 `#if 0` 屏蔽，默认沿用 netdev 的 addr 并打印）。

### 27.5 驱动探测与移除

- `rk_gmac_probe()` 路径：
	1) `stmmac_get_platform_resources()` 获取寄存器/IRQ 资源；
	2) `stmmac_probe_config_dt()` 解析 DT 生成 `plat_stmmacenet_data`；
	3) 注入 Rockchip 私有回调：`plat-&gt;fix_mac_speed`、`get_eth_addr`、`integrated_phy_power`；
	4) `rk_gmac_setup()` 建立 `bsp_priv`，读取 `clock_in_out/tx_delay/rx_delay`、regmap 句柄与 `phy_iface`；
	5) `rk_gmac_clk_init()`、`rk_gmac_powerup()`；
	6) 交给主驱动 `stmmac_dvr_probe()` 完成通用初始化；
	7) 收尾失败路径会调用 `rk_gmac_powerdown()` 与 `stmmac_remove_config_dt()` 清理。

### 27.6 设备树要点（Rockchip）

以 RK3568 为例（属性名以源码为准）：

### Rockchip glue 初始化流程（Mermaid）

```mermaid
flowchart TD
	P0[probe]
	P1[rk_gmac_setup]
	P2[rk_gmac_clk_init]
	P3[rk_gmac_powerup]
	P4[set_to_* (RGMII/RMII/SGMII)]
	P5[integrated_phy_power]
	P6[pm_runtime_enable]
	P7[stmmac_dvr_probe]
	P0 --&gt; P1 --&gt; P2 --&gt; P3 --&gt; P4 --&gt; P5 --&gt; P6 --&gt; P7
```

```dts
gmac0: ethernet@fe2a0000 {
		compatible = &quot;rockchip,rk3568-gmac&quot;;
		reg = &lt;0x0 0xfe2a0000 0x0 0x10000&gt;;
		interrupts = &lt;GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH&gt;;
		phy-mode = &quot;rgmii&quot;;                // 或 &quot;rgmii-id&quot;/&quot;rmii&quot;/&quot;sgmii&quot;
		rockchip,grf = &lt;&amp;sys_grf&gt;;
		rockchip,php_grf = &lt;&amp;php_grf&gt;;      // RK3588/RK3568 某些模式需要
		rockchip,xpcs = &lt;&amp;xpcs&gt;;            // SGMII/QSGMII 需要

		clock_in_out = &quot;input&quot;;            // 或 &quot;output&quot;（决定 RMII 参考时钟方向）
		tx_delay = &lt;0x30&gt;;                  // 根据板级布线与 PHY 建议
		rx_delay = &lt;0x20&gt;;

		clocks = &lt;&amp;cru ...&gt;;                // mac_clk_rx/tx、clk_mac_speed 等
		clock-names = &quot;mac_clk_rx&quot;, &quot;mac_clk_tx&quot;, &quot;clk_mac_speed&quot;, ...;
		phy-handle = &lt;&amp;phy0&gt;;
};
```

排错提示：

- `rockchip,grf/php_grf/xpcs` 任一缺失都会导致接口模式或 PCS 配置失败；
- `clock_in_out` 与实际走线方向不符时，RMII 将无法建链或速率异常；
- RGMII 延时往往需要实测微调（配合示波器或 PHY loopback）。

---

## 第 28 章：DWC QoS glue（`dwmac-dwc-qos-eth.c`）

本文件对应 Synopsys DWC Ethernet QoS v4.10a 的 glue 层。在你的仓库中，它通过 VMM 平台接口完成资源获取，并对 AXI/DMA 能力做了默认配置。

### 28.1 设备树解析到 AXI/DMA 参数

`dwc_eth_dwmac_config_dt()`：

- 读取 `snps,en-lpi`，映射到 `plat-&gt;axi-&gt;axi_lpi_en`；
- `snps,write-requests`/`snps,read-requests` → `axi_wr_osr_lmt/axi_rd_osr_lmt`，注意函数中与老驱动兼容，解析后执行 `--`（硬件寄存器的 reset 值为 1，对应 &quot;1 outstanding&quot;）；
- `snps,burst-map` bitmask 转换为 `axi_blen[]`（支持 4/8/16/32/64/128/256）；
- 能力位：强制开启 `has_gmac4=1`、`dma_cfg-&gt;aal=1`、`tso_en=1`、`pmt=1`。

### 28.2 资源获取与主驱动接入

- 使用 VMM 的 `vmm_devtree_irq_parse_map()` 获取中断号，`vmm_devtree_request_regmap()` 映射寄存器；
- 调用 `stmmac_probe_config_dt()` 生成 `plat_stmmacenet_data` 并注入上述配置；
- 直接 `stmmac_dvr_probe()` 进入通用主驱动；
- `remove` 路径则 `stmmac_dvr_remove()` + `stmmac_remove_config_dt()` 清理。

与上游 Linux 的差异：上游常见还有 TEGRA EQoS 的子驱动，这里已以 `#if 0` 屏蔽（示例保留以供参考）。

---

## 第 29 章：Ring vs Chain 模式的实现差异（`ring_mode.c` / `chain_mode.c`）

两种 DMA 描述符组织模式在 DWMAC4 中都可用，区别主要体现在 DES3 的用途与 Jumbo/SPH 处理。驱动通过 `stmmac_mode_ops` 抽象。

### 29.1 Chain 模式（`chain_mode.c`）

- 初始化：`init_dma_chain()` 将每个描述符的 `des3` 指向下一个元素，最后一个回指到头，形成显式链表；
- Jumbo 处理：`jumbo_frm()` 按 `BUF_SIZE_2KiB/8KiB` 分片，逐片 `dma_map_single` 并准备描述符；
- `refill_desc3()`/`clean_desc3()`：当启用 HW 时间戳且使用普通描述符时，硬件可能在 TX/RX 上覆写 `des3` 保存时间戳值，因此驱动在回填/清理时要把 `des3` 恢复为链指针，保持链形态的正确性；
- 适用性：在需要明确链指针、或硬件时间戳与普通描述符共存时，Chain 模式易于维护；

### 描述符布局对比（Mermaid）

```mermaid
flowchart LR
	subgraph Chain[Chain 模式]
		C1[desc0 des3=next]
		C2[desc1 des3=next]
		C3[desc2 des3=next]
		C4[descN des3=desc0]
		C1 --&gt; C2 --&gt; C3 --&gt; C4
	end
	subgraph Ring[Ring 模式]
		R1[desc0 des3=buf2]
		R2[desc1 des3=buf2]
		R3[desc2 des3=buf2]
		R4[descN des3=buf2]
		R1 --- R2 --- R3 --- R4
	end
```

### 29.2 Ring 模式（`ring_mode.c`）

- DES3 作为数据缓冲扩展：RING 模式下不使用 `des3` 做链指针，而常用于指向第二片缓冲（例如 16KiB RX 缓冲将 `des3 = des2 + 8KiB`）；
- Jumbo 处理：当 `nopaged_len &gt; 8KiB` 时，首片 `bmax=8KiB`，第二片余量作为下一描述符；均设置 `is_jumbo=true` 以便清理；
- `set_16kib_bfsize()` 与 `init_desc3()`：当 MTU &gt; 8KiB 时，推荐使用 16KiB RX buffer 策略，并在初始化时预填 DES3；
- `refill_desc3()`：在 16KiB 情形下重设 `des3`；`clean_desc3()` 清理时间戳/大包情况下的 `des3`；
- 适用性：配合 SPH 与大缓冲时，Ring 模式可减少描述符数量与缓存 miss，提高吞吐。

### 29.3 选择建议与注意事项

- 若平台支持 16KiB RX buffer，Ring 模式更高效；
- 启用 HW 时间戳但使用普通描述符时，Chain 模式需在回填/清理时特别维护 `des3`；
- 无论哪种模式：
	- OWN 必须最后写；
	- Jumbo 需评估 `dma_buf_sz`、MTL FIFO 与 PBL 参数，避免丢包或过度分片；
	- 记得在 RX 回填时及时推进 RPTR（`stmmac_set_rx_tail_ptr`）。

---

## 第 30 章：MMC 统计计数器详解（`mmc_core.c`）

MAC Management Counters 用于长期观测链路质量与收发行为。你的仓库同时支持 DWMAC（千兆）与 DWXGMAC（万兆）两套计数器。

### 30.1 启用与屏蔽

- `stmmac_mmc_setup()`：在 `stmmac_hw_setup()` 中调用，写 `MMC_CNTRL` 启用统计；
- `intr_all_mask()`：默认屏蔽全部 MMC 中断（计数按需读取即可）。

### 30.2 常用字段（DWMAC）

- TX：`MMC_TX_OCTETCOUNT_GB/G`、`TX_FRAMECOUNT_GB/G`、`TX_UNDERFLOW_ERROR`、`TX_PAUSE_FRAME`、`TX_VLAN_FRAME_G`；
- RX：`MMC_RX_OCTETCOUNT_GB/G`、`RX_FRAMECOUNT_GB`、`RX_CRC_ERROR`、`RX_ALIGN_ERROR`、`RX_RUN_ERROR`、`RX_JABBER`、`RX_LENGTH_ERROR`、`RX_FIFO_OVERFLOW`、`RX_VLAN_FRAMES_GB`；
- IPC/IPv4/IPv6/TCP/UDP 派生计数：用于快速评估协议分布与错误；
- TSN/FPE 相关（若支持）：`TX_FPE_FRAG/HOLD_REQ`、`RX_PKT_ASSEMBLY_*`、`RX_FPE_FRAG`。

`dwmac_mmc_read()` 每次读取会将硬件计数清零（&quot;read-to-clear&quot;），驱动内部累加到 `struct stmmac_counters` 中。

### 30.3 DWXGMAC（10G）差异

- 64 位计数拆分为两次 32 位读：`dwxgmac_read_mmc_reg()` 将 `low + (high &lt;&lt; 32)` 聚合；若溢出则钳制到 32 位最大值（驱动内部约定）。
- 字段名称与偏移不同，但语义相似（TX/RX good/bad、长度分布、error、VLAN、LPI）。

### 30.4 实战排障思路

- CRC/ALIGN/RUN/JABBER 错飙：优先检查线缆/PHY/接口模式（RGMII 延时、RMII 时钟方向）；
- `RX_FIFO_OVERFLOW` 高：MTL/DMA 阈值与 PBL 偏 aggressive，或合并参数导致 IRQ 响应不及时；
- `TX_UNDERFLOW_ERROR`：TX FIFO 较小且突发长度/仲裁不当，尝试降低 PBL 或开启 SF；
- VLAN 相关计数验证 VLAN 路由与过滤是否按预期生效。

---

## 小结与后续

本轮新增了 Rockchip 平台 glue、DWC QoS glue、Ring/Chain 模式细节与 MMC 统计的实战章节，均以你仓库中的源码为依据。接下来若你提供目标板信息（SoC/PHY/接口模式/参考时钟），我可以：

- 补充该板的 DT 示例（含精确的 `grf/php_grf/xpcs` 连接与时钟名）；
- 给出 RGMII 延时初值建议与校准步骤；
- 提供一组面向该板的 ethtool/PTP/压测脚本，帮助快速验证与调优。
</code></pre>
<hr>
<h2 id="%E7%AC%AC-31-%E7%AB%A0%E6%9D%BF%E7%BA%A7-bring-up-%E4%BD%9C%E6%88%98%E6%89%8B%E5%86%8C%E4%B8%80%E6%AD%A5%E6%AD%A5%E8%B7%91%E9%80%9A%E7%BD%91%E5%8F%A3">第 31 章：板级 Bring-up 作战手册（一步步跑通网口）</h2>
<p>目标：在未知或全新板卡上，从“上电”到“稳态收发”的可执行步骤。适用 DWMAC4 平台（含 Rockchip/DWC QoS 等）。</p>
<p>31.1 前置检查（硬件/连线/资料）</p>
<ul>
<li>原理图：确认 MAC→PHY 连接模式（RGMII/RMII/SGMII/QSGMII）、时钟方向（RMII in/out）、RGMII 延时是否在 MAC/PHY/走线上实现；</li>
<li>参考时钟：PTP/PHY/MAC RX/TX 时钟来源与频率；</li>
<li>复位/电源：PHY 有无外部 LDO/PMIC 控制，Reset GPIO 逻辑电平与时序；</li>
<li>片上资源：GRF/XPCS/PIPE-GRF 的寄存器物理基址（Rockchip），AXI/MTL 队列能力；</li>
<li>以太网磁石/端口：回环测试所需的物理链接路径可达。</li>
</ul>
<p>31.2 设备树最小化配置</p>
<ul>
<li>正确填写 compatible、reg、interrupts；</li>
<li>设置 phy-mode 与 phy-handle；</li>
<li>把 clocks/clock-names/resets 匹配到 SoC 时钟树与复位控制器；</li>
<li>若为 Rockchip：补齐 rockchip,grf/php_grf/xpcs 与 clock_in_out/tx_delay/rx_delay；</li>
<li>AXI/DMA 参数先用保守值：PBL=16、fixed-burst on、read/write outstanding 小值；</li>
<li>暂时关闭高阶功能（TSO/TBS/RSS/EEE），降低变量。</li>
</ul>
<p>31.3 Probe 阶段检查（dmesg/日志要点）</p>
<ul>
<li>驱动打印的 HW feature（队列数、TSO/EEE/TS 等）与预期一致；</li>
<li>MAC/DMA/MTL 初始化无错误码；</li>
<li>MDIO 注册成功，能扫描到 PHY，<code>stmmac_init_phy()</code> attach 成功；</li>
<li>对于 SGMII/QSGMII：PCS/XPCS 初始化成功，无超时；</li>
<li>若出现“clk/pm/serdes”相关失败，优先回看时钟树与电源域。</li>
</ul>
<p>31.4 建链与基础连通</p>
<ul>
<li><code>ip link set eth0 up</code> 之后，观察 link up/down；</li>
<li><code>ethtool eth0</code> 查看速率/双工/协商；</li>
<li><code>ping</code> 同网段设备确认 L2/L3 基础连通；</li>
<li>观察 ethtool -S：rx_packets/tx_packets 是否随之增长；</li>
<li>MMC 计数：CRC/ALIGN/RUN/JABBER 是否为 0；异常则回查接口模式与时钟/延时。</li>
</ul>
<p>31.5 收发路径健康度</p>
<ul>
<li>RX：打开 DebugFS（若可用），查看 RX ring OWN/cur_rx/dirty_rx 是否流转；发生“总是 OWN=DMA”时，检查回填与 RPTR 更新；</li>
<li>TX：查看 tx_tail 推进、<code>stmmac_tx_err()</code> 是否触发；</li>
<li>IRQ：/proc/interrupts 中中断计数是否增长；若无中断，尝试禁用合并/RIWT 或切换到轮询验证路径。</li>
</ul>
<p>31.6 性能与稳定性冒烟</p>
<ul>
<li>小流量延迟：小包 ping（禁用 TSO/GRO）确认稳态延迟；</li>
<li>大包吞吐：MTU 1500/9000 下跑 iperf3，观察 CPU 与中断数；</li>
<li>压力场景：并发连接/多队列开 RSS，校验不丢包；</li>
<li>PTP：若有需求，跑 ptp4l/phc2sys 观察偏差走势，确保硬件时间戳工作正常。</li>
</ul>
<p>31.7 问题分层定位</p>
<ul>
<li>物理层：链路灯、PHY 寄存器（MDIO dump）、SGMII/PCS 链路状态；</li>
<li>MAC/MTL/DMA：寄存器快照、队列映射、PBL/阈值；</li>
<li>内存一致性：wmb/rmb、IOMMU map/snoop、缓存属性；</li>
<li>栈与应用：ethtool offload、GRO/RPS/XPS、irqbalance。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-32-%E7%AB%A0%E5%90%88%E5%B9%B6%E7%AD%96%E7%95%A5%E8%B0%83%E4%BC%98riwt-%E4%B8%8E%E8%BD%AF%E4%BB%B6-coalesce">第 32 章：合并策略调优（RIWT 与软件 coalesce）</h2>
<p>目标：在“中断数/CPU 占用/延迟”之间找平衡点。</p>
<p>32.1 概念速览</p>
<ul>
<li>RIWT（RX Interrupt Watchdog）：硬件定时器，当 RX 完成后一段时间未触发中断则强制触发，适合低 PPS 报文抖动时保证及时性；</li>
<li>软件 coalesce：以“每 N 帧或 M 微秒”触发中断，典型用于 TX；</li>
<li>两者组合：RX 侧以 RIWT 为主、辅以预算/预算未满提前中断；TX 侧以帧数合并为主。</li>
</ul>
<p>32.2 驱动中的落点</p>
<ul>
<li><code>stmmac_main.c: stmmac_hw_setup()</code> 会根据平台参数决定 <code>use_riwt</code> 与默认 RIWT；</li>
<li><code>stmmac_rx()</code> 中在回填时根据 <code>use_rx_wd</code> 设置 OWN，影响 RIWT 行为；</li>
<li>TX 合并：<code>tx_coal_frames</code> 影响 <code>set_tx_ic()</code> 的设置时机；</li>
<li>设备树或平台参数可提供初始 coalesce 设置，运行时可通过 ethtool 调整（若路径启用）。</li>
</ul>
<p>32.3 调参建议（经验值起步）</p>
<ul>
<li>
<p>低时延优先：</p>
<ul>
<li>RX RIWT 设为较小值（例如 32–64 μs），RX 软件合并关闭或很小；</li>
<li>TX 每 1–8 帧中断一次，保证 ACK/控制流及时；</li>
<li>开启 SF 模式有助于延迟稳定。</li>
</ul>
</li>
<li>
<p>吞吐优先：</p>
<ul>
<li>RX RIWT 增大到 128–256 μs，结合 GRO；</li>
<li>TX 合并每 32–64 帧触发；</li>
<li>评估 PBL/Outstanding 以减少仲裁成本。</li>
</ul>
</li>
<li>
<p>小包 PPS：</p>
<ul>
<li>适当降低 RX RIWT 并开启 RSS 分散到多核；</li>
<li>关注 LPI/EEE 可能带来的时延阶跃，必要时关闭 EEE。</li>
</ul>
</li>
</ul>
<p>32.4 观测指标</p>
<ul>
<li>中断数（/proc/interrupts）、软中断占比（/proc/softirqs）、CPU 利用率；</li>
<li>平均/尾延迟（p99/p999）、丢包率；</li>
<li>ethtool -S 中 TX/RX coalesce 相关统计（若实现）。</li>
</ul>
<p>32.5 常见误区</p>
<ul>
<li>RIWT 与软件 coalesce 重叠导致“迟迟不中断”：确保两者阈值协同；</li>
<li>合并过度引发队列积压、MTL FIFO 溢出；</li>
<li>与 IRQ 亲和/irqbalance 的耦合：合并参数变动后要重新评估亲和性。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-33-%E7%AB%A0%E5%9C%B0%E5%9D%80%E5%AE%BD%E5%BA%A6iommu-%E4%B8%8E-eame%E6%89%A9%E5%B1%95%E5%9C%B0%E5%9D%80">第 33 章：地址宽度、IOMMU 与 EAME（扩展地址）</h2>
<p>33.1 背景</p>
<ul>
<li>SoC 可能支持 32/34/40 位物理地址；</li>
<li>DMA mask 与一致性掩码需要与总线/IOMMU 匹配；</li>
<li>DWMAC4 支持 EAME（Extended Address Enable），允许 64 位地址（视实现）。</li>
</ul>
<p>33.2 驱动/平台要点</p>
<ul>
<li>在 probe 期间设置 DMA 掩码：<code>dma_set_mask_and_coherent()</code>，失败则回退到较低位宽；</li>
<li><code>plat-&gt;dma_cfg-&gt;eame</code>：当内存高地址可达且硬件支持时应置位；</li>
<li>描述符地址设置：<code>stmmac_set_desc_addr()</code> 会在 extend_desc 模式下处理高位；</li>
<li>IOMMU 存在时：确保设备域已 attach、streaming 映射开销可接受；大页/页池可优化 RX。</li>
</ul>
<p>33.3 Buffer 尺寸与对齐</p>
<ul>
<li>16KiB RX buffer 策略需考虑 IOMMU 页尺寸与映射开销；</li>
<li>对齐：缓存线对齐可减少写放大；</li>
<li>物理连续性：大缓冲可优先使用页面池（若集成）。</li>
</ul>
<p>33.4 调试与故障</p>
<ul>
<li>典型症状：DMA 映射失败、地址截断、硬件读写超时；</li>
<li>检查：打印 DMA 地址高位、确认 EAME 与掩码设置、IOMMU 日志（页表/权限）；</li>
<li>回退策略：临时禁用 EAME 或将缓冲拆分为 8KiB 片以验证链路正确性。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-34-%E7%AB%A0%E7%A1%AE%E5%AE%9A%E6%80%A7%E7%BD%91%E7%BB%9Ctsn%E7%9B%B8%E5%85%B3%E8%83%BD%E5%8A%9B%E6%A6%82%E8%A7%88tbsestfpe">第 34 章：确定性网络（TSN）相关能力概览（TBS/EST/FPE）</h2>
<p>34.1 能力与路径</p>
<ul>
<li>TBS（Time-Based Send）：基于时间戳的发送调度，结合扩展描述符，需与 PTP 对时配合；</li>
<li>EST（Time-Aware Shaper/TAPRIO）：基于时隙的门控调度，通常通过 <code>tc qdisc taprio</code> 下发门控列表，驱动经 <code>stmmac_tc_ops</code> 配置 MTL 门控；</li>
<li>FPE（Frame Preemption）：允许高优先级帧抢占低优先级帧，涉及 MAC Merge 层；</li>
<li>CBS（Credit-Based Shaper）：音视频类带宽整形；</li>
<li>你的仓库中相关入口在 <code>hwif.h</code> 的 <code>stmmac_tc_ops</code>，具体实现随 IP/版本差异可能部分留空或受 <code>#if 0</code> 影响。</li>
</ul>
<p>34.2 与 PTP 的关系</p>
<ul>
<li>EST/TBS 均对时钟一致性敏感：PHC 与系统时钟偏移需在 μs 级以内；</li>
<li>规划调度需考虑 DMA 取数/MTL 排队/MAC 发射/物理层延迟；</li>
<li>稳态运行中监控丢门/错窗，必要时增设 Guard Band。</li>
</ul>
<p>34.3 实施建议</p>
<ul>
<li>先验证 PTP 稳定度（第 38 章方法），再上线 EST/TBS；</li>
<li>从 1 个优先级/单门控表开始，验证门控开合是否按预期影响吞吐与延迟；</li>
<li>FPE 需要对端支持并协调门限/最小片段；</li>
<li>工具链：<code>tc</code>, <code>pmc</code>（PTP management client），<code>tsntool</code>（若有）。</li>
</ul>
<h3 id="est-%E6%97%B6%E9%97%B4%E8%BD%B4%E7%A4%BA%E6%84%8Fmermaid">EST 时间轴示意（Mermaid）</h3>
<pre class="hljs"><code><div>gantt
	dateFormat  HH:mm:ss
	title TSN EST 门控调度示意
	section Queue0
	Gate Open    :active, 00:00:00, 00:00:10
	Gate Close   : 00:00:10, 00:00:10
	Gate Open    : 00:00:20, 00:00:10
	section Queue1
	Gate Close   :active, 00:00:00, 00:00:10
	Gate Open    : 00:00:10, 00:00:10
	Gate Close   : 00:00:20, 00:00:10
</div></code></pre>
<p>34.4 限制与兼容</p>
<ul>
<li>不同 DWMAC 版本对 EST/FPE 的寄存器支持差异较大；</li>
<li>与 TSO/TBS 互斥关系：单队列内通常不可混用；</li>
<li>与 VLAN/优先级标记耦合：确保优先级映射到正确的 MTL 队列。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-35-%E7%AB%A0phypcs-%E6%B7%B1%E5%85%A5%E4%B8%8E%E9%93%BE%E8%B7%AF%E7%AE%A1%E7%90%86">第 35 章：PHY/PCS 深入与链路管理</h2>
<p>35.1 phylib 与 phylink</p>
<ul>
<li>本仓库采用 phylib 经典路径（<code>stmmac_mdio.c</code> + <code>stmmac_init_phy()</code>）；</li>
<li>现代内核可选 phylink（统一处理 RGMII/SGMII/USXGMII 等多制式），但需驱动配合改造；</li>
<li>对于 SGMII/QSGMII：通过 XPCS/SerDes 配置接口速率与自协商，<code>dwmac-rk.c</code> 中 <code>xpcs_setup()</code> 提供参考。</li>
</ul>
<p>35.2 Pause/AN/速率切换</p>
<ul>
<li>Pause 能力在 PHY 协商，驱动在 <code>stmmac_flow_ctrl()</code> 应用结果；</li>
<li>速率变化回调：<code>plat-&gt;fix_mac_speed</code>（Rockchip：<code>rk_fix_speed</code>）在链路变更时设置 MAC/时钟；</li>
<li>RGMII 延时：<code>dwmac_rk_set_rgmii_delayline()</code> 支持运行期调整，结合示波器微调 TX/RX 时序。</li>
</ul>
<p>35.3 诊断与调试</p>
<ul>
<li>MDIO 直读：Clause22/45 读 PHY/SERDES 关键寄存器，确认 AN 完成、链路伙伴能力；</li>
<li>PCS 状态：读取 XPCS 链路状态/误码计数；</li>
<li>典型问题：
<ul>
<li>RGMII RX 抖动/误码：调 <code>rx_delay</code>；</li>
<li>RMII 50MHz 来源错误：确认 <code>clock_in_out</code>；</li>
<li>SGMII 不 up：确认 XPCS 上电序列与 reference clock。</li>
</ul>
</li>
</ul>
<p>35.4 链路策略建议</p>
<ul>
<li>数据中心/延迟敏感：禁用对称 pause，或仅启用 RX pause；</li>
<li>家宽/不丢包优先：启用对称 pause；</li>
<li>多速率切换场景：启用 AN，但给出合理的降速回退逻辑。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-36-%E7%AB%A0irq-%E4%BA%B2%E5%92%8Crpsxpsgro-%E4%B8%8E%E5%A4%9A%E9%98%9F%E5%88%97%E5%AE%9E%E8%B7%B5">第 36 章：IRQ 亲和、RPS/XPS、GRO 与多队列实践</h2>
<p>36.1 中断亲和与多队列绑定</p>
<ul>
<li>每个 DMA 通道通常有独立 IRQ（或共享并带 channel 标识），建议：
<ul>
<li>将 RX 队列 i 的 IRQ 绑到 CPU i（或同 NUMA 节点）；</li>
<li>开启 <code>irqbalance</code> 时，固定关键队列以避免迁移抖动；</li>
<li>配合 <code>ethtool -X</code> 设置 RSS indir 表，确保流在核间均匀分布。</li>
</ul>
</li>
</ul>
<p>36.2 RPS/XPS</p>
<ul>
<li>RPS（Receive Packet Steering）：在软中断层转发到目标 CPU，适合单队列设备；</li>
<li>XPS（Transmit Packet Steering）：按队列映射将 TX 发送固定到期望 CPU，降低跨核竞争；</li>
<li>操作接口：<code>/proc/sys/net/core/{rps_sock_flow_entries}</code> 与 per-queue <code>rps_cpus</code>/<code>xps_cpus</code>；</li>
<li>与 stmmac：多 RX 队列 + RSS 场景优先，RPS 次之；XPS 可把相应 TXQ 固定到收包核，形成 RX/TX 成对亲和。</li>
</ul>
<p>36.3 GRO/GSO 协同</p>
<ul>
<li>GRO 提高合并粒度，PPS 下降但延迟增大；</li>
<li>若硬件支持 TSO/GSO，保持 GRO 打开有助于端到端吞吐；</li>
<li>对延迟敏感服务（RPC/交易）：适度降低 GRO 超时或关闭。</li>
</ul>
<p>36.4 实操步骤（示意）</p>
<ul>
<li>关闭 irqbalance，手动设置亲和；</li>
<li><code>ethtool -x/-X</code> 设置 RSS；</li>
<li>配置 RPS/XPS 掩码；</li>
<li>压测并观察 p99 延迟、丢包与中断数；</li>
<li>固化为 systemd 脚本或发行版网络配置。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-37-%E7%AB%A0%E9%A9%B1%E5%8A%A8%E7%BB%9F%E8%AE%A1%E4%B8%8E-ethtool-%E6%98%A0%E5%B0%84">第 37 章：驱动统计与 ethtool 映射</h2>
<p>37.1 驱动内部统计</p>
<ul>
<li><code>struct stmmac_extra_stats</code>（<code>priv-&gt;xstats</code>）记录大量内部事件：
<ul>
<li>tx/rx_clean、tx_timeout、irq_service、mac_link_up/down、lpi 事件；</li>
<li>错误路径计数（dma_tx/rx_hard_error、fifo_overflow 等）。</li>
</ul>
</li>
<li>MMC 统计：通过 <code>mmc_core.c</code> 聚合，read-to-clear + 软件累加。</li>
</ul>
<p>37.2 ethtool -S 输出</p>
<ul>
<li>常见项：<code>tx_packets/tx_bytes/rx_packets/rx_bytes/rx_crc_errors</code> 等；</li>
<li>多队列下：per-queue 统计（若实现），帮助定位热点队列或不均衡问题；</li>
<li>自定义统计：可在驱动侧扩展 netdev_stats 或私有 ethtool counters。</li>
</ul>
<p>37.3 监控建议</p>
<ul>
<li>生产环境定期抓取：ethtool -S、MMC 聚合、/proc/interrupts；</li>
<li>设阈监控：CRC/ALIGN/RUN/JABBER 突增报警；</li>
<li>性能画像基线：同负载/同固件下的中断/CPU/PPS 偏差预警。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-38-%E7%AB%A0ptp-%E9%AA%8C%E8%AF%81%E6%B5%81%E7%A8%8B%E7%AB%AF%E5%88%B0%E7%AB%AF">第 38 章：PTP 验证流程（端到端）</h2>
<p>38.1 前置条件</p>
<ul>
<li>确认硬件支持 TX/RX HWTS，<code>stmmac_init_ptp()</code> 成功且 /dev/ptpX 存在；</li>
<li>对端设备或本机 loopback 支持 PTP（ptp4l/pmc 可用）。</li>
</ul>
<p>38.2 单机自检</p>
<ul>
<li>读取/设置 PHC 时间：<code>phc_ctl get/set</code>（或 <code>clock_gettime</code> on /dev/ptpX）；</li>
<li><code>pmc -u -b 0 'GET CLOCK_DESCRIPTION'</code> 查看能力；</li>
<li><code>phc2sys -s CLOCK_REALTIME -c /dev/ptp0 -O 0</code> 验证本机对时路径。</li>
</ul>
<p>38.3 主从对时</p>
<ul>
<li>设备 A 运行 <code>ptp4l -i eth0 -m -H -2</code>，设备 B 同样运行并观测 offset；</li>
<li>稳态 offset 观测（p99）应在 1–10 μs（千兆铜缆常见范围，受硬件/温漂影响）；</li>
<li>畸变排查：
<ul>
<li>addend 计算或 sub-second increment 配置错误；</li>
<li>EEE/LPI 导致时延抖动（验证时关闭 EEE）；</li>
<li>队列/流控/拥塞引起的排队延迟。</li>
</ul>
</li>
</ul>
<p>38.4 辅助验证</p>
<ul>
<li>抓取 TX/RX 时间戳（<code>SO_TIMESTAMPING</code>），比对内核 socket 层时间；</li>
<li>验证 TBS/EST 时，记录发射计划时间与实际 TX timestamp 差值，收集分布。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-39-%E7%AB%A0%E8%84%9A%E6%9C%AC%E5%8C%96%E5%B7%A5%E5%85%B7%E4%B8%8E%E6%B5%8B%E8%AF%95%E6%B8%85%E5%8D%95%E5%8F%AF%E6%8A%84%E5%8F%AF%E7%94%A8">第 39 章：脚本化工具与测试清单（可抄可用）</h2>
<p>39.1 初始化脚本片段（示意）</p>
<ul>
<li>设置基本 offload</li>
<li>选择 RSS/XPS 亲和</li>
<li>基本 coalesce/RIWT 参数</li>
<li>开启/关闭 EEE</li>
</ul>
<p>39.2 压测脚本</p>
<ul>
<li>iperf3 单/多流，记录 CPU/中断/吞吐；</li>
<li>小包 ping 延迟采样；</li>
<li>混合负载（UDP+TCP）。</li>
</ul>
<p>39.3 PTP 验证脚本</p>
<ul>
<li>ptp4l + phc2sys 联动，记录 offset 时间序列；</li>
<li>addend/sub-second 校准辅助计算。</li>
</ul>
<p>39.4 采集与归档</p>
<ul>
<li>ethtool -S /proc/interrupts /sys/kernel/debug/stmmac/* 定时采集；</li>
<li>版本/环境（内核/固件/DT）元数据同档保存，便于回溯。</li>
</ul>
<hr>
<h2 id="%E7%AC%AC-40-%E7%AB%A0%E4%B8%80%E9%A1%B5%E7%BA%B8%E9%80%9F%E6%9F%A5%E4%B8%8E%E6%94%B6%E5%B0%BE">第 40 章：一页纸速查与收尾</h2>
<p>40.1 Bring-up 关键点</p>
<ul>
<li>PHY/PCS：模式/时钟/延时；</li>
<li>DMA/AXI：PBL/Outstanding/固定突发；</li>
<li>队列：RSS/映射/权重；</li>
<li>合并：RIWT + SW coalesce；</li>
<li>校验：OWN 写序、尾指针更新、缓存同步。</li>
</ul>
<p>40.2 性能调优抓手</p>
<ul>
<li>SF vs 阈值模式；</li>
<li>GRO/RSS/XPS；</li>
<li>流控策略；</li>
<li>16KiB RX buffer 与 SPH；</li>
<li>IRQ 亲和与 NUMA。</li>
</ul>
<p>40.3 排错路径</p>
<ul>
<li>不收包：RX OWN/RPTR、IRQ、PCS、RIWT；</li>
<li>不发包：TPDR/OWN、DMA 错误、AXI 拒绝；</li>
<li>错帧多：RGMII 延时/时钟、线缆/磁石；</li>
<li>PTP 漂移：addend/sub-second、EEE、温漂。</li>
</ul>
<p>—— 完 ——</p>
<hr>
<h2 id="%E9%99%84%E9%80%BB%E8%BE%91%E5%AE%8C%E6%95%B4%E6%80%A7%E8%87%AA%E6%A3%80%E7%AE%80%E7%89%88">附：逻辑完整性自检（简版）</h2>
<ul>
<li>架构到实现：第 1 章提供总体框图；第 2–6 章覆盖平台、抽象与 MAC/DMA/描述符；</li>
<li>数据路径：第 7–9 章 + 第 14 章有 TX/RX/IRQ 详解与顺序图；</li>
<li>控制面：第 10–11 章覆盖 PTP 与 MDIO/PHY；</li>
<li>进阶能力：第 12、15–19 章涵盖 VLAN/RSS/EEE/TSO/TBS/TC；</li>
<li>SoC glue：第 27–28 章落地 Rockchip 与 DWC QoS；</li>
<li>模式与计数：第 29–30 章对 Ring/Chain 与 MMC 统计补充；</li>
<li>实操与调优：第 31–40 章给出 bring-up、coalesce、IOMMU、TSN、IRQ/RPS/XPS、统计、PTP、自化脚本与速查。</li>
</ul>
<p>结论：文档从主干到细节全链路覆盖，新增 Mermaid 图让路径更直观；如需更进一步，可按目标板信息定制 DT 与脚本以实现“一键起网”。</p>

</body>

</html>